Skip to content

bun-types: accept the { name, cause } options object in the DOMException constructor - #39323

Open
robobun wants to merge 1 commit into
mainfrom
farm/bb2049a4/domexception-ctor-options-types
Open

bun-types: accept the { name, cause } options object in the DOMException constructor#39323
robobun wants to merge 1 commit into
mainfrom
farm/bb2049a4/domexception-ctor-options-types

Conversation

@robobun

@robobun robobun commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Problem

  • Against bun-types, new DOMException("boom", { name: "AbortError", cause: err }) fails to compile: error TS2345: Argument of type '{ name: string; cause: Error; }' is not assignable to parameter of type 'string'. The { name } and { cause } forms fail the same way.
  • The runtime accepts all of them: JSDOMExceptionDOMConstructor::construct (src/jsc/bindings/webcore/JSDOMException.cpp:136-153) reads name and cause from an object second argument and falls back to treating the argument as the name string. Node accepts the same form (its test/parallel/test-domexception-cause.js runs in Bun's suite), and @types/node declares it (web-globals/domexception.d.ts).
  • packages/bun-types/globals.d.ts:948 declared only new (message?: string, name?: string).

Fix

  • Adds the overload new (message?: string, options?: { name?: string | undefined; cause?: unknown }): DOMException to the DOMException declaration. This is the fixing line; the rest of that hunk is re-indentation.
  • Declares the variable through Bun.__internal.UseLibDomIfAvailable<"DOMException", ...>, like the other web globals in the file. lib.dom.d.ts also declares var DOMException, and TypeScript requires repeated var declarations to have identical types, which the old declaration met by being a copy of lib.dom's. With the wrapper, lib.dom's declaration is used when lib.dom is loaded, so in that configuration the options form stays rejected exactly as before (the three new entries in the "checks with lib.dom.d.ts" list record that), and the overload applies everywhere else.
  • Why this shape: it mirrors what construct() accepts. name is optional and an explicit undefined is treated as absent (hence string | undefined, which also matters under exactOptionalPropertyTypes); cause is stored as given, whatever its type, so it is unknown, matching ErrorOptions.cause. The two overloads are the same two @types/node declares. @types/node itself is not affected: its var DOMException is conditional on onmessage existing on globalThis, which bun-types declares (index.d.ts:32), so it takes whatever bun-types declares.
  • Verified:
    • test/integration/bun-types/fixture/globals.ts gains the string form, the three options forms, the cause type and a rejected second argument. Without the .d.ts change the checks without lib.dom.d.ts and tsgo cases fail with the three TS2345 errors above; with it the whole file passes (bun test test/integration/bun-types/bun-types.test.ts, 15 pass).
    • The existing single-file tsc case, the only fixture check that also runs under a debug build, gets one { name, cause } line and is renamed accordingly. bun bd test on the file: fails without the .d.ts change, 3 pass / 12 skip with it. If test(bun-types): replace the tsgo and Bun.mmap spawns with one whole-fixture tsc run, enforced by a lint #39270 lands first, that block goes away and the fixture lines are the coverage.
    • tsc -p packages/bun-types is clean.
    • Runtime probe of every form under bun 1.4.0 and node 26.3.0 below.

Background

  • bun-types and lib.dom.d.ts both declare the web globals. Interfaces merge, but a var declared twice must have the identical type, so bun-types declares such variables as UseLibDomIfAvailable<Name, T> (bun.d.ts:58): when lib.dom is loaded (detected by onabort existing on globalThis) it resolves to lib.dom's type for Name, otherwise to T. The cost is that Bun-only surface is unavailable when lib.dom is loaded; the "checks with lib.dom.d.ts" list in bun-types.test.ts is the record of that surface.
  • @types/node declares its web globals as typeof globalThis extends { onmessage: any; X: infer T } ? T : { ... }, deferring to a DOM-like environment when one is present. bun-types declares onmessage so that @types/node defers to it, which is why the declaration users see for DOMException is the one in globals.d.ts and not @types/node's.
  • test/integration/bun-types packs packages/bun-types, installs it into a copy of fixture/ and type-checks the fixture with and without lib.dom. Most of those cases drive TypeScript in-process and are skipped on debug builds; the single-file tsc case is the one that runs under either build.
Runtime probe
const inner = new Error("inner");
for (const [label, e] of [
  ["string name", new DOMException("boom", "AbortError")],
  ["{name, cause}", new DOMException("boom", { name: "AbortError", cause: inner })],
  ["{name}", new DOMException("boom", { name: "NotFoundError" })],
  ["{cause}", new DOMException("boom", { cause: 42 })],
  ["{}", new DOMException("boom", {})],
  ["{cause: undefined}", new DOMException("boom", { cause: undefined })],
]) console.log(label, { name: e.name, code: e.code, hasCause: "cause" in e, cause: e.cause });

bun 1.4.0:

string name          {"name":"AbortError","code":20,"hasCause":false}
{name, cause}        {"name":"AbortError","code":20,"hasCause":true,"cause":"Error(inner)"}
{name}               {"name":"NotFoundError","code":8,"hasCause":false}
{cause}              {"name":"Error","code":0,"hasCause":true,"cause":42}
{}                   {"name":"Error","code":0,"hasCause":false}
{cause: undefined}   {"name":"Error","code":0,"hasCause":true}

node 26.3.0 accepts the same inputs; the only difference is that it reports name as "undefined" when the options object has no name, which does not affect the declaration (name is optional either way).

…ion constructor

The runtime (JSDOMException.cpp) and Node both accept an options object as
the second argument, but the declaration only allowed a name string.
The var is now declared through UseLibDomIfAvailable so the extra overload
does not conflict with lib.dom.d.ts when that is loaded.
@robobun
robobun requested a review from alii as a code owner August 16, 2026 07:02
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 minutes

Limit details: You’ve used all 5 included reviews currently available under your plan.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 33d4c7f3-6105-4f69-b422-360fc5ce4a76

📥 Commits

Reviewing files that changed from the base of the PR and between aec33f5 and c0e8125.

📒 Files selected for processing (3)
  • packages/bun-types/globals.d.ts
  • test/integration/bun-types/bun-types.test.ts
  • test/integration/bun-types/fixture/globals.ts

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

@robobun

robobun commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 12:03 AM PT - Aug 16th, 2026

@robobun, your commit c0e8125 is building: #99255

@robobun

robobun commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator Author

Status: ready for review at c0e8125. Types and test changes only; no src/ diff. The automated review found nothing to change and is deferring to the packages/bun-types code owner.

Reproduced by type-checking new DOMException("boom", { name: "AbortError", cause: err }) against packages/bun-types on main (TS2345, parameter type string); the same call runs fine under bun 1.4.0 and node 26.3.0 (probe output in the description). The .d.ts change is the one added overload in globals.d.ts; the new fixture lines in fixture/globals.ts fail with that overload absent and pass with it, under both the release run of bun-types.test.ts and the debug build.

@claude claude Bot left a comment

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.

I reviewed this and found no issues. Deferring approval since packages/bun-types/ has a CODEOWNER.

What was reviewed:

  • The new overload matches the runtime (JSDOMExceptionDOMConstructor::construct reads name/cause from an object arg) and @types/node's shape.
  • Wrapping the var in UseLibDomIfAvailable follows the same pattern as the neighboring web globals; confirmed it avoids the duplicate-var-declaration conflict with lib.dom.
  • Fixture line numbers (globals.ts:340-342, col 37) line up with the three new expected diagnostics in the lib.dom case, and err is in scope from the earlier const err = new Error(...).
  • The @ts-expect-error on new DOMException("asdf", 20) errors under both overload sets, so it holds with and without lib.dom.
Extended reasoning...

Overview

This PR adds a second constructor overload to the DOMException type declaration in packages/bun-types/globals.d.ts so that new DOMException(msg, { name, cause }) type-checks. The declaration is also switched from a bare declare var to the Bun.__internal.UseLibDomIfAvailable<"DOMException", ...> wrapper, matching the pattern used by every other web global in the file. The rest of the diff is test coverage: six new assertions in fixture/globals.ts, three new expected-error entries in the checks with lib.dom.d.ts list of bun-types.test.ts (recording that lib.dom's own signature still rejects the options object when lib.dom is loaded), and one line added to the single-file tsc smoke check that runs on debug builds.

Security risks

None. This is a pure TypeScript declaration change with no runtime code; the tests only drive tsc over fixtures.

Level of scrutiny

Low. The one substantive line is a constructor overload that mirrors both the actual C++ implementation and @types/node. The UseLibDomIfAvailable wrapping is mechanical — the file already has ~30 declarations using the identical shape. I verified the fixture line/column numbers in the new expected-diagnostic entries match where the object literals land after the insertions, that err referenced on line 340 is the Error declared earlier in the fixture, and that the @ts-expect-error guard on new DOMException("asdf", 20) is satisfied under both the with-lib.dom and without-lib.dom configurations (a number matches neither string nor the options object).

Other factors

The PR description includes verification that the full test file passes (15 pass) and that it fails without the .d.ts change, satisfying the fails-for-the-right-reason requirement. packages/bun-types/ is CODEOWNER-gated, which is why I'm deferring rather than approving despite the change being straightforward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant