Skip to content

feat(sql-orm-client): expand and simplify output types#283

Open
aqrln wants to merge 4 commits intomainfrom
tml-2139-prettify-query-result-types-with-recursive-mapped-type
Open

feat(sql-orm-client): expand and simplify output types#283
aqrln wants to merge 4 commits intomainfrom
tml-2139-prettify-query-result-types-with-recursive-mapped-type

Conversation

@aqrln
Copy link
Copy Markdown
Member

@aqrln aqrln commented Apr 2, 2026

Closes: https://linear.app/prisma-company/issue/TML-2139/prettify-query-result-types-with-recursive-mapped-type

Query result types in sql-orm-client are currently unexpanded intersections full of internal utility types, making them hard to read in IDE tooltips and error messages.

This change applies a recursive mapped type at the top-level return positions so that IDE tooltips and hover types display fully-evaluated object literals.

Before:

image

After:

image

Summary by CodeRabbit

  • Refactor

    • Improved type inference for query result types, providing cleaner and more readable type hints in code editors for collection queries, selections, and aggregations.
  • Tests

    • Added type assertion tests to validate compile-time type behavior.
  • Chores

    • Reorganized type utilities and updated package dependencies.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

A new SimplifyDeep recursive type utility is introduced to the utils package, simplifying intersection types and nested objects. It is applied to row types in SQL ORM Collection and GroupedCollection classes, and replaces local SimplifyDeep definitions in mongo-orm by establishing a centralized export.

Changes

Cohort / File(s) Summary
SimplifyDeep Type Utility
packages/1-framework/0-foundation/utils/src/simplify-deep.ts, packages/1-framework/0-foundation/utils/src/exports/simplify-deep.ts
New recursive TypeScript type utility that flattens intersection types, preserves terminal types (primitives, Date, RegExp, Uint8Array, functions), converts readonly arrays to mutable, and recursively simplifies nested object properties.
SQL ORM Type Simplification
packages/3-extensions/sql-orm-client/src/collection.ts, packages/3-extensions/sql-orm-client/src/grouped-collection.ts
Updated Collection and GroupedCollection row types to wrap results with SimplifyDeep, including default generic parameter, include(), select(), and aggregate() return types.
Utils Package Exports
packages/1-framework/0-foundation/utils/package.json, packages/1-framework/0-foundation/utils/tsdown.config.ts
Added new export entry ./simplify-deep and included corresponding source entry point in build configuration.
Mongo ORM Migration
packages/2-mongo-family/5-query-builders/orm/package.json, packages/2-mongo-family/5-query-builders/orm/src/exports/index.ts, packages/2-mongo-family/5-query-builders/orm/src/types.ts
Migrated SimplifyDeep from local definition to centralized utils export; added @prisma-next/utils dependency and updated re-exports.
Demo Application Update
examples/mongo-demo/package.json, examples/mongo-demo/src/server.ts
Updated SimplifyDeep import source from @prisma-next/mongo-orm to @prisma-next/utils/simplify-deep; added utils dependency.
Test Coverage
packages/1-framework/0-foundation/utils/test/simplify-deep.test-d.ts, packages/3-extensions/sql-orm-client/test/simplify-deep.test.ts
Added comprehensive TypeScript declaration tests for SimplifyDeep behavior (primitives, nested objects, arrays, unions) and integration tests verifying Collection row type simplification with first(), select(), and include().
Test Configuration
packages/1-framework/0-foundation/utils/vitest.config.ts
Enabled Vitest typecheck configuration for declaration test files (*.test-d.ts).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Types once tangled, now refined,
Intersections flattened, simplified,
Nested objects bloom so clear,
SimplifyDeep brings order here,
From utils' heart, a gift we share! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(sql-orm-client): expand and simplify output types' directly and specifically describes the main change—applying SimplifyDeep to expand and simplify query result type representations in sql-orm-client.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2139-prettify-query-result-types-with-recursive-mapped-type

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 2, 2026

Open in StackBlitz

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-runtime@283

@prisma-next/family-mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/family-mongo@283

@prisma-next/sql-runtime

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-runtime@283

@prisma-next/family-sql

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/family-sql@283

@prisma-next/middleware-telemetry

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/middleware-telemetry@283

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/extension-paradedb@283

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/extension-pgvector@283

@prisma-next/postgres

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/postgres@283

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-orm-client@283

@prisma-next/sqlite

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sqlite@283

@prisma-next/target-mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/target-mongo@283

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/adapter-mongo@283

@prisma-next/driver-mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/driver-mongo@283

@prisma-next/contract

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/contract@283

@prisma-next/utils

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/utils@283

@prisma-next/config

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/config@283

@prisma-next/errors

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/errors@283

@prisma-next/framework-components

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/framework-components@283

@prisma-next/operations

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/operations@283

@prisma-next/contract-authoring

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/contract-authoring@283

@prisma-next/ids

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/ids@283

@prisma-next/psl-parser

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/psl-parser@283

@prisma-next/psl-printer

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/psl-printer@283

@prisma-next/cli

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/cli@283

@prisma-next/emitter

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/emitter@283

@prisma-next/migration-tools

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/migration-tools@283

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/vite-plugin-contract-emit@283

@prisma-next/runtime-executor

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/runtime-executor@283

@prisma-next/mongo-codec

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-codec@283

@prisma-next/mongo-contract

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-contract@283

@prisma-next/mongo-value

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-value@283

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-contract-psl@283

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-contract-ts@283

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-emitter@283

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-schema-ir@283

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-query-ast@283

@prisma-next/mongo-orm

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-orm@283

@prisma-next/mongo-pipeline-builder

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-pipeline-builder@283

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-lowering@283

@prisma-next/mongo-wire

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-wire@283

@prisma-next/sql-contract

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-contract@283

@prisma-next/sql-errors

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-errors@283

@prisma-next/sql-operations

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-operations@283

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-schema-ir@283

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-contract-psl@283

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-contract-ts@283

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-contract-emitter@283

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-lane-query-builder@283

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-relational-core@283

@prisma-next/sql-builder

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-builder@283

@prisma-next/target-postgres

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/target-postgres@283

@prisma-next/target-sqlite

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/target-sqlite@283

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/adapter-postgres@283

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/adapter-sqlite@283

@prisma-next/driver-postgres

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/driver-postgres@283

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/driver-sqlite@283

commit: 10de666

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/3-extensions/sql-orm-client/test/simplify-deep.test-d.ts (1)

74-75: Use double cast for test mocks.

Per coding guidelines, test mocks should use double casts (as unknown as X) to make the unsafe boundary explicit.

♻️ Suggested fix
   const runtime = createMockRuntime();
-  const context = {} as ExecutionContext<TestContract>;
+  const context = {} as unknown as ExecutionContext<TestContract>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/3-extensions/sql-orm-client/test/simplify-deep.test-d.ts` around
lines 74 - 75, The test mock `context` is using a single cast which hides the
unsafe conversion; change the declaration where `context` is assigned (`const
context = {} as ExecutionContext<TestContract>`) to use a double cast (`as
unknown as ExecutionContext<TestContract>`) so the unsafe boundary is explicit;
leave `createMockRuntime()` as-is and update only the `context` variable's
casting.
packages/3-extensions/sql-orm-client/src/types.ts (1)

28-35: Readonly arrays lose their readonly modifier.

The array branch returns SimplifyDeep<Element>[] (mutable), which strips readonly from input types like readonly T[]. If any row fields are typed as readonly arrays, the simplified type will become mutable.

If preserving readonly is desired:

♻️ Suggested fix to preserve readonly
 export type SimplifyDeep<T> =
   T extends readonly (infer Element)[]
-    ? SimplifyDeep<Element>[]
+    ? readonly SimplifyDeep<Element>[]
     : T extends string | number | boolean | bigint | symbol | Date | Uint8Array
       ? T
       : T extends object
         ? { [K in keyof T]: SimplifyDeep<T[K]> }
         : T;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/3-extensions/sql-orm-client/src/types.ts` around lines 28 - 35, The
SimplifyDeep utility is stripping readonly from array types because the array
branch returns SimplifyDeep<Element>[] (mutable); update the array branch in
SimplifyDeep so it preserves readonly (e.g., when T extends readonly (infer
Element)[] return a readonly array of SimplifyDeep<Element>), ensuring readonly
T[] inputs remain readonly in the output; modify the SimplifyDeep definition
(the branch matching readonly (infer Element)[]) to produce a readonly
SimplifyDeep<Element>[] rather than a mutable array.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/3-extensions/sql-orm-client/src/types.ts`:
- Around line 28-35: The SimplifyDeep utility is stripping readonly from array
types because the array branch returns SimplifyDeep<Element>[] (mutable); update
the array branch in SimplifyDeep so it preserves readonly (e.g., when T extends
readonly (infer Element)[] return a readonly array of SimplifyDeep<Element>),
ensuring readonly T[] inputs remain readonly in the output; modify the
SimplifyDeep definition (the branch matching readonly (infer Element)[]) to
produce a readonly SimplifyDeep<Element>[] rather than a mutable array.

In `@packages/3-extensions/sql-orm-client/test/simplify-deep.test-d.ts`:
- Around line 74-75: The test mock `context` is using a single cast which hides
the unsafe conversion; change the declaration where `context` is assigned
(`const context = {} as ExecutionContext<TestContract>`) to use a double cast
(`as unknown as ExecutionContext<TestContract>`) so the unsafe boundary is
explicit; leave `createMockRuntime()` as-is and update only the `context`
variable's casting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 5f49d154-0964-462d-a77d-f8515e353d75

📥 Commits

Reviewing files that changed from the base of the PR and between 39fd54b and 131787e.

📒 Files selected for processing (4)
  • packages/3-extensions/sql-orm-client/src/collection.ts
  • packages/3-extensions/sql-orm-client/src/grouped-collection.ts
  • packages/3-extensions/sql-orm-client/src/types.ts
  • packages/3-extensions/sql-orm-client/test/simplify-deep.test-d.ts

@aqrln aqrln marked this pull request as draft April 2, 2026 10:19
@aqrln aqrln force-pushed the tml-2139-prettify-query-result-types-with-recursive-mapped-type branch from 131787e to c25c1dd Compare April 2, 2026 10:21
@aqrln aqrln marked this pull request as ready for review April 2, 2026 10:30
Copy link
Copy Markdown
Contributor

@wmadden wmadden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preemptively approving — the approach is sound and the implementation is clean. Please address or respond to the inline comments before merging; no re-review needed.

Blocking (2): F01 (double-wrapping at each chaining step — apply at terminal methods instead), F02 (add test for deeply chained operations).

Non-blocking (3): F03 (readonly array erasure), F04 (raise to @prisma-next/utils), F05 (polymorphic model forward risk).

Comment on lines 130 to 134
export class Collection<
TContract extends SqlContract<SqlStorage>,
ModelName extends string,
Row = DefaultModelRow<TContract, ModelName>,
Row = SimplifyDeep<DefaultModelRow<TContract, ModelName>>,
State extends CollectionTypeState = DefaultCollectionTypeState,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F01 — Blocking: SimplifyDeep applied at every chaining step instead of terminal methods

The default Row is already SimplifyDeep<DefaultModelRow<...>>. When include() returns SimplifyDeep<Row & { posts: ... }>, this becomes SimplifyDeep<SimplifyDeep<...> & { ... }>. Each chaining step adds another wrapper. For users.select('name').include('posts'), that's three nested SimplifyDeep evaluations — O(N×K) work for N chained ops with K total keys.

Suggestion: Apply SimplifyDeep only at the terminal methods (first(), all(), toArray()) instead of at each builder step. Builder methods accumulate raw intersections internally; only the final result type gets simplified. This reduces overhead to exactly one pass regardless of chain length and is architecturally cleaner — simplification is a presentation concern, not a builder concern.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each SimplifyDeep step receives AlreadyFlatObject & { newField: ... } as input — not a deeply nested tree. TypeScript caches the resolution of the inner SimplifyDeep, so step 2 isn't re-traversing step 1's keys. Look at what actually happens:

    SimplifyDeep<
      Row & {

Row is already a resolved flat mapped type from the previous step. The outer SimplifyDeep just flattens one intersection of FlatObj & { posts: ... } — a single pass over the combined keys, not a re-walk of the entire history.

Also, if you defer to terminal methods, then hovering over any intermediate builder step shows raw intersections like { id: number; name: string; ... } & { posts: PostRow[] } & { invitedBy: UserRow | null }.

Comment thread packages/3-extensions/sql-orm-client/test/simplify-deep.test-d.ts
Comment thread packages/3-extensions/sql-orm-client/src/types.ts Outdated
Comment thread packages/3-extensions/sql-orm-client/src/types.ts Outdated
Comment thread packages/3-extensions/sql-orm-client/src/types.ts Outdated
Closes: https://linear.app/prisma-company/issue/TML-2139/prettify-query-result-types-with-recursive-mapped-type

Query result types in `sql-orm-client` are currently unexpanded
intersections full of internal utility types, making them hard to read
in IDE tooltips and error messages.

This change applies a recursive mapped type at the top-level return
positions so that IDE tooltips and hover types display fully-evaluated
object literals.
@aqrln aqrln force-pushed the tml-2139-prettify-query-result-types-with-recursive-mapped-type branch from c25c1dd to dc9edce Compare April 15, 2026 19:13
@aqrln aqrln force-pushed the tml-2139-prettify-query-result-types-with-recursive-mapped-type branch from 0005e2d to 55cb9a9 Compare April 15, 2026 20:49
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/1-framework/0-foundation/utils/test/simplify-deep.test-d.ts (1)

17-20: Use strict type-identity checks for branded types instead of expectTypeOf.

Line 19 uses toEqualTypeOf() which performs structural comparison and erases brand information, risking false positives where the brand erosion goes undetected. The test explicitly asserts "branded primitives pass through," so strict type-identity verification is essential.

💡 Proposed refactor
   test('branded primitives pass through', () => {
     type Branded = string & { readonly __brand: true };
-    expectTypeOf<SimplifyDeep<Branded>>().toEqualTypeOf<Branded>();
+    type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends
+      (<T>() => T extends B ? 1 : 2)
+      ? true
+      : false;
+    type Expect<T extends true> = T;
+    type _brandedPreserved = Expect<Equal<SimplifyDeep<Branded>, Branded>>;
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/1-framework/0-foundation/utils/test/simplify-deep.test-d.ts` around
lines 17 - 20, The test currently uses
expectTypeOf<SimplifyDeep<Branded>>().toEqualTypeOf<Branded>() which does a
structural compare and can lose the brand; replace this with a strict
type-identity assertion: create or reuse a compile-time IsIdentical<A,B> utility
and assert IsIdentical<SimplifyDeep<Branded>, Branded> is true (e.g. via a
type-level Assert or conditional type that fails compilation if not identical)
so the branded primitive identity is enforced for the test named "branded
primitives pass through" and references SimplifyDeep and Branded.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/1-framework/0-foundation/utils/test/simplify-deep.test-d.ts`:
- Line 14: The test uses the type-form assertion
expectTypeOf<SimplifyDeep<never>>().toEqualTypeOf<never>() which fails with the
current Vitest; replace it with the documented value-form workaround used
elsewhere: create a value cast to SimplifyDeep<never> (e.g. use a plain value
cast like undefined as SimplifyDeep<never>) and call expectTypeOf on that value,
then assert equality to never via toEqualTypeOf; apply the same change pattern
where you see the same failing assertion (look for
expectTypeOf<...>().toEqualTypeOf<never> and SimplifyDeep usages).

---

Nitpick comments:
In `@packages/1-framework/0-foundation/utils/test/simplify-deep.test-d.ts`:
- Around line 17-20: The test currently uses
expectTypeOf<SimplifyDeep<Branded>>().toEqualTypeOf<Branded>() which does a
structural compare and can lose the brand; replace this with a strict
type-identity assertion: create or reuse a compile-time IsIdentical<A,B> utility
and assert IsIdentical<SimplifyDeep<Branded>, Branded> is true (e.g. via a
type-level Assert or conditional type that fails compilation if not identical)
so the branded primitive identity is enforced for the test named "branded
primitives pass through" and references SimplifyDeep and Branded.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 8cb11c27-2103-46a9-8ba2-a1bc417083a9

📥 Commits

Reviewing files that changed from the base of the PR and between 55cb9a9 and f8ff24a.

📒 Files selected for processing (3)
  • packages/1-framework/0-foundation/utils/src/simplify-deep.ts
  • packages/1-framework/0-foundation/utils/test/simplify-deep.test-d.ts
  • packages/1-framework/0-foundation/utils/vitest.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/1-framework/0-foundation/utils/src/simplify-deep.ts

expectTypeOf<SimplifyDeep<null>>().toEqualTypeOf<null>();
expectTypeOf<SimplifyDeep<undefined>>().toEqualTypeOf<undefined>();
expectTypeOf<SimplifyDeep<unknown>>().toEqualTypeOf<unknown>();
expectTypeOf<SimplifyDeep<never>>().toEqualTypeOf<never>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify existing never-assertion patterns used across declaration tests.
rg -nP --type=ts 'toEqualTypeOf<never>\(\)' -g '**/*.test-d.ts'
rg -nP --type=ts 'toEqualTypeOf\(undefined as never\)' -g '**/*.test-d.ts'

Repository: prisma/prisma-next

Length of output: 604


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check if type test files are included in test configuration
if [ -f "vitest.config.ts" ] || [ -f "vitest.config.mts" ]; then
  echo "=== Vitest Configuration ===" 
  head -50 vitest.config.* 2>/dev/null | grep -A5 -B5 "test-d" || echo "No test-d pattern found in config start"
fi

# Count all instances of the problematic pattern
echo "=== Pattern: toEqualTypeOf<never>() instances ==="
rg -c 'toEqualTypeOf<never>\(\)' -g '**/*.test-d.ts' || echo "0"

# List files that need fixing
echo "=== Files using problematic pattern ==="
rg -l 'toEqualTypeOf<never>\(\)' -g '**/*.test-d.ts'

# Check for any type test errors in the build
if [ -f "pnpm-lock.yaml" ]; then
  echo "=== Package manager: pnpm detected ==="
fi

Repository: prisma/prisma-next

Length of output: 474


Use the documented workaround pattern for never type assertions.

Line 14 uses toEqualTypeOf<never>(), which does not compile with the current Vitest version. Replace with the value-form workaround as already used in the integration test suite.

Proposed fix
-    expectTypeOf<SimplifyDeep<never>>().toEqualTypeOf<never>();
+    expectTypeOf<SimplifyDeep<never>>().toEqualTypeOf(undefined as never);

Note: The same issue exists in packages/2-mongo-family/1-foundation/mongo-codec/test/codecs.test-d.ts:51 and should be fixed with the same pattern.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
expectTypeOf<SimplifyDeep<never>>().toEqualTypeOf<never>();
expectTypeOf<SimplifyDeep<never>>().toEqualTypeOf(undefined as never);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/1-framework/0-foundation/utils/test/simplify-deep.test-d.ts` at line
14, The test uses the type-form assertion
expectTypeOf<SimplifyDeep<never>>().toEqualTypeOf<never>() which fails with the
current Vitest; replace it with the documented value-form workaround used
elsewhere: create a value cast to SimplifyDeep<never> (e.g. use a plain value
cast like undefined as SimplifyDeep<never>) and call expectTypeOf on that value,
then assert equality to never via toEqualTypeOf; apply the same change pattern
where you see the same failing assertion (look for
expectTypeOf<...>().toEqualTypeOf<never> and SimplifyDeep usages).

@aqrln aqrln enabled auto-merge (squash) April 15, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants