Skip to content

fix(client-generator-ts): type browser null singleton exports#29408

Open
raashish1601 wants to merge 2 commits intoprisma:mainfrom
raashish1601:fix/prisma-28581-pnpm-nulltypes-portable-exports
Open

fix(client-generator-ts): type browser null singleton exports#29408
raashish1601 wants to merge 2 commits intoprisma:mainfrom
raashish1601:fix/prisma-28581-pnpm-nulltypes-portable-exports

Conversation

@raashish1601
Copy link
Copy Markdown

@raashish1601 raashish1601 commented Mar 27, 2026

Summary

  • add explicit typeof runtime.* annotations to the generated browser-side DbNull, JsonNull, and AnyNull singleton exports
  • keep the emitted declarations portable in pnpm monorepos instead of leaving declaration emit to infer names that trigger TS2742
  • add a focused generator regression that checks the emitted internal/prismaNamespaceBrowser.ts text directly

Testing

  • pnpm.cmd install --frozen-lockfile
  • pnpm.cmd --filter @prisma/client-generator-ts... build
  • pnpm.cmd --filter @prisma/client-generator-ts exec vitest run tests/generator.test.ts -t "emits portable typed null singleton exports in the browser namespace"
  • pnpm.cmd exec eslint packages/client-generator-ts/src/TSClient/NullTypes.ts packages/client-generator-ts/tests/generator.test.ts
  • git diff --check HEAD~1..HEAD

Fixes #28581

Summary by CodeRabbit

  • Refactor

    • Enhanced TypeScript type annotations for null singleton constants for stricter typing.
  • Tests

    • Added coverage for typed null singleton exports in browser builds.
    • Improved test cleanup to ensure generator shutdown runs even on failures.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bb7a9cbf-e43b-4925-bcee-73888e0d2f08

📥 Commits

Reviewing files that changed from the base of the PR and between 5f73175 and 5654e5c.

📒 Files selected for processing (1)
  • packages/client-generator-ts/tests/generator.test.ts

Walkthrough

Exports for the null singletons (DbNull, JsonNull, AnyNull) were given explicit typeof runtime.X type annotations; tests were updated and a new test added to verify the generator emits these typed exports (browser namespace). Generator shutdown is now guaranteed with try/finally in tests.

Changes

Cohort / File(s) Summary
Null type annotations
packages/client-generator-ts/src/TSClient/NullTypes.ts
Added explicit type annotations: export const DbNull: typeof runtime.DbNull = runtime.DbNull, JsonNull, and AnyNull to make exported singleton types portable and avoid TS2742 inference issues.
Generator tests
packages/client-generator-ts/tests/generator.test.ts
Wrapped existing minimal test generator usage in try { ... } finally { generator.stop() }; added emits portable typed null singleton exports in the browser namespace async test that generates with skipDownload: true, asserts the browser namespace file contains the new typeof runtime.X export patterns, and also uses try/finally to ensure generator.stop().
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(client-generator-ts): type browser null singleton exports' clearly and specifically describes the main change: adding type annotations to the null singleton exports in the generated client code.
Linked Issues check ✅ Passed The PR addresses all coding requirements from issue #28581: adds explicit typeof annotations to DbNull, JsonNull, and AnyNull exports, and includes a regression test verifying the emitted browser namespace file contains properly typed exports.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the TS2742 errors in pnpm monorepos: type annotations for null exports and test improvements to ensure proper generator behavior.
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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/client-generator-ts/tests/generator.test.ts (1)

89-144: ⚠️ Potential issue | 🟡 Minor

Ensure generator.stop() always runs with try/finally.

In Line 143 and Line 161, cleanup is on the success path only. If an assertion or file read fails, generator.stop() is skipped.

Suggested hardening
 test('minimal', async () => {
   const generator = await getGenerator({
     schemaPath: path.join(__dirname, 'schema.prisma'),
     printDownloadProgress: false,
     skipDownload: true,
     registry,
   })
-
-  const manifest = omit(generator.manifest!, ['version'])
+  try {
+    const manifest = omit(generator.manifest!, ['version'])
 
-  if (manifest.requiresEngineVersion?.length !== 40) {
-    throw new Error(`Generator manifest should have "requiresEngineVersion" with length 40`)
-  }
-  manifest.requiresEngineVersion = 'ENGINE_VERSION_TEST'
+    if (manifest.requiresEngineVersion?.length !== 40) {
+      throw new Error(`Generator manifest should have "requiresEngineVersion" with length 40`)
+    }
+    manifest.requiresEngineVersion = 'ENGINE_VERSION_TEST'
 
-  // ... assertions ...
+    // ... assertions ...
 
-  await generator.generate()
-  const clientDir = path.join(__dirname, 'generated')
-  expect(fs.existsSync(clientDir)).toBe(true)
-  expect(fs.existsSync(path.join(clientDir, 'client.ts'))).toBe(true)
-
-  generator.stop()
+    await generator.generate()
+    const clientDir = path.join(__dirname, 'generated')
+    expect(fs.existsSync(clientDir)).toBe(true)
+    expect(fs.existsSync(path.join(clientDir, 'client.ts'))).toBe(true)
+  } finally {
+    generator.stop()
+  }
 })
 
 test('emits portable typed null singleton exports in the browser namespace', async () => {
   const generator = await getGenerator({
     schemaPath: path.join(__dirname, 'schema.prisma'),
     printDownloadProgress: false,
     skipDownload: true,
     registry,
   })
-
-  await generator.generate()
-  const clientDir = path.join(__dirname, 'generated')
-  const browserNamespace = fs.readFileSync(path.join(clientDir, 'internal', 'prismaNamespaceBrowser.ts'), 'utf8')
-  expect(browserNamespace).toContain('export const DbNull: typeof runtime.DbNull = runtime.DbNull')
-  expect(browserNamespace).toContain('export const JsonNull: typeof runtime.JsonNull = runtime.JsonNull')
-  expect(browserNamespace).toContain('export const AnyNull: typeof runtime.AnyNull = runtime.AnyNull')
-
-  generator.stop()
+  try {
+    await generator.generate()
+    const clientDir = path.join(__dirname, 'generated')
+    const browserNamespace = fs.readFileSync(path.join(clientDir, 'internal', 'prismaNamespaceBrowser.ts'), 'utf8')
+    expect(browserNamespace).toContain('export const DbNull: typeof runtime.DbNull = runtime.DbNull')
+    expect(browserNamespace).toContain('export const JsonNull: typeof runtime.JsonNull = runtime.JsonNull')
+    expect(browserNamespace).toContain('export const AnyNull: typeof runtime.AnyNull = runtime.AnyNull')
+  } finally {
+    generator.stop()
+  }
 })

Also applies to: 146-162

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/client-generator-ts/tests/generator.test.ts` around lines 89 - 144,
The test should ensure generator.stop() is always called by wrapping generator
usage in a try/finally: locate the test function named "test('minimal')" (and
the other similar test around the second block) where getGenerator(...) is
awaited and generator.generate() is called, move generator.stop() into a finally
block so it runs even if assertions or file operations fail; keep generator
variable in scope (declared before try) and call generator.stop() in the finally
to guarantee cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/client-generator-ts/tests/generator.test.ts`:
- Around line 89-144: The test should ensure generator.stop() is always called
by wrapping generator usage in a try/finally: locate the test function named
"test('minimal')" (and the other similar test around the second block) where
getGenerator(...) is awaited and generator.generate() is called, move
generator.stop() into a finally block so it runs even if assertions or file
operations fail; keep generator variable in scope (declared before try) and call
generator.stop() in the finally to guarantee cleanup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a8bea333-e61f-4028-bee9-ff0d4582f03f

📥 Commits

Reviewing files that changed from the base of the PR and between 5fece0a and 5f73175.

📒 Files selected for processing (2)
  • packages/client-generator-ts/src/TSClient/NullTypes.ts
  • packages/client-generator-ts/tests/generator.test.ts

@jacek-prisma
Copy link
Copy Markdown
Contributor

I would like to see a reproduction of the issue this is meant to fix. Ideally this reproduction would be turned into a test, we could make it an E2E test in packages/client/tests/e2e/. Do you have a way to reproduce it?

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.

[Prisma 7.0.0] TypeScript TS2742 errors with pnpm monorepo - cannot resolve @prisma/client-runtime-utils types

3 participants