Skip to content

bun-types: keep generic process.removeListener and off signatures visible with @types/node 24 - #40004

Merged
Jarred-Sumner merged 2 commits into
mainfrom
farm/bd2ca903/fix-process-removelistener-types
Aug 30, 2026
Merged

Jarred-Sumner merged 2 commits into
mainfrom
farm/bd2ca903/fix-process-removelistener-types

Conversation

@robobun

@robobun robobun commented Aug 21, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • With @types/node@24 installed, tsc rejects process.removeListener("SIGINT", fn) and process.off(...) with error TS2345: Argument of type '"SIGINT"' is not assignable to parameter of type '"memoryPressure"' (bun-types 1.4.0 memoryPressure overrides break process.removeListener/off with @types/node@24 #40003).
  • The cause is packages/bun-types/overrides.d.ts:112-114. It declares off and removeListener overloads for the memoryPressure event on NodeJS.Process. @types/node@24 does not declare these two methods on Process, it only inherits them from EventEmitter. A method declared on a derived interface hides the inherited overloads, so memoryPressure became the only accepted event name.

Fix

  • Re-declare the generic (event: string | symbol, listener: (...args: any[]) => void): this signatures for off and removeListener next to the memoryPressure overloads.
  • This restores exactly what EventEmitter provides on @types/node@24. On @types/node@26, which declares the same generic signatures on Process directly, the merge adds an identical overload and nothing changes.
  • The other overridden methods (on, once, addListener, prependListener, prependOnceListener, emit) are declared on Process by @types/node@24, so declaration merging keeps them visible and they need no change.
  • Verified: new case in test/integration/bun-types/bun-types.test.ts pins @types/node@24 and runs tsc over removeListener/off/memoryPressure calls. It fails on main with the exact error above. The full bun-types integration suite passes (16/16).

Background


[review] gate passed · iteration 1 · 2 files touched

fails on main (without fix)
ASAN without fix: BUILD FAILED (no junit output)
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/integration/bun-types/bun-types.test.ts
ninja: Entering directory `/workspace/bun/build/debug'
[1/26] gen generated_host_exports.rs
generated_host_exports.rs: 122 exports (host=5, lazy=10, generic=107, rust=0); 244 extern-C blocks audited
[2/26] gen cpp.rs (cppbind)
[3/26] gen JS modules (bundle-modules)
Preprocess modules (7475ms)
Bundle modules (60ms)
Postprocesss modules (199ms)
Bundle Functions (490ms)
Generate Code (35ms)

[8.27s] Bundled "src/js" for development
  2787 kb
  197 internal modules
  13 native modules
  50 internal functions across 16 files
[3/8] cargo bun_runtime → libbun_runtime.a
[4/8] cc obj/codegen/InternalModuleRegistryConstants.S.o
FAILED: rust-target/x86_64-unknown-linux-gnu/debug/libbun_runtime.a 
/workspace/bun/build/release/bun /workspace/bun/scripts/build/stream.ts rust --console --cwd=/workspace/bun --env=CARGO_TERM_COLOR=always --env=BUN_CODEGEN_DIR=/workspace/bun/build/debug/codegen --env=CC=/usr/lib/llvm-21/bin/clang --env=CXX=/usr/lib/llvm-21/bin/clang++ --env=AR=/usr/lib/llvm-21/bin/llvm-ar -
... (truncated)

release without fix: 1 FAILED
bun test v1.4.1-canary.1 (7e07e7a89)

test/integration/bun-types/bun-types.test.ts:
(pass) @types/bun integration test > building and packing bun-types leaves packages/bun-types untouched [0.10ms]
(pass) @types/bun integration test > packed bun-types includes CLAUDE.md [0.34ms]
(pass) @types/bun integration test > basic type checks > checks without lib.dom.d.ts [2875.25ms]
(pass) @types/bun integration test > tsgo (TypeScript 7 native preview) > checks without lib.dom.d.ts [553.59ms]
(pass) @types/bun integration test > Bun.mmap > MMapOptions accepts offset and size [48.09ms]
(pass) @types/bun integration test > TextDecoder > accepts the encoding labels the runtime supports [49.86ms]
(pass) @types/bun integration test > TextDecoder > the fixture label table matches the runtime [0.79ms]
(pass) @types/bun integration test > Event and EventTarget > lib.dom's composedPath() declaration wins when lib.dom is loaded [78.63ms]
(pass) @types/bun integration test > Event and EventTarget > the Node-style composedPath() tuple applies without lib.dom [51.17ms]
570 |       });
571 | 
572 |       const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr
... (truncated)
passes on PR (with fix)
ASAN with fix: 12 skipped
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/integration/bun-types/bun-types.test.ts
bun test v1.4.1 (d578a8c70)

test/integration/bun-types/bun-types.test.ts:
(pass) @types/bun integration test > building and packing bun-types leaves packages/bun-types untouched [2.04ms]
(pass) @types/bun integration test > packed bun-types includes CLAUDE.md [5.88ms]
(skip) @types/bun integration test > basic type checks > checks without lib.dom.d.ts
(skip) @types/bun integration test > tsgo (TypeScript 7 native preview) > checks without lib.dom.d.ts
(pass) @types/bun integration test > Bun.mmap > MMapOptions accepts offset and size [745.09ms]
(pass) @types/bun integration test > TextDecoder > accepts the encoding labels the runtime supports [682.14ms]
(pass) @types/bun integration test > TextDecoder > the fixture label table matches the runtime [38.91ms]
(pass) @types/bun integration test > Event and EventTarget > lib.dom's composedPath() declaration wins when lib.dom is loaded [718.69ms]
(pass) @types/bun integration test > Event and EventTarget > the Node-style composedPath() tuple appl
... (truncated)

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 773ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[1/23] gen generated_host_exports.rs
generated_host_exports.rs: 122 exports (host=5, lazy=10, generic=107, rust=0); 244 extern-C blocks audited
[2/23] gen cpp.rs (cppbind)
[3/23] gen JS modules (bundle-modules)
Preprocess modules (7439ms)
Bundle modules (34ms)
Postprocesss modules (40ms)
Bundle Functions (439ms)
Generate Code (23ms)

[7.98s] Bundled "src/js" for production
  2594 kb
  197 internal modules
  13 native modules
  50 internal functions across 16 files
[3/8] cargo bun_runtime → libbun_runtime.a
�[1m�[92m   Compiling�[0m bun_core v0.0.0 (/workspace/bun/src/bun_core)
�[1m�[92m   Compiling�[0m bun_errno v0.0.0 (/workspace/bun/src/errno)
�[1m�[92m   Compiling�[0m bun_ptr v0.0.0 (/workspace/bun/src/ptr)
�[1m�[92m   Compiling�[0m bun_boringssl_sys v0.0.0 (/workspace/bun/src/boringssl_sys)
�[1m�[92m   Compiling�[0m bun_safety v0.0.0 (/workspace/bun/src/safety)
�[1m�[92m   Compiling�[0m bun_base64 v0.0.0 (/workspace/bun/src/base64)
�[1m�[92m   Compiling�[0m bun_cares_sys v0.0.0 (/workspace/bun/src/ca
... (truncated)
diff hotspot
packages/bun-types/overrides.d.ts            |  8 +++++
 test/integration/bun-types/bun-types.test.ts | 53 ++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)

gate history · 4 passed · 0 rejected · iteration 1

evidence per changed file
file                                          reads  edits  tests
packages/bun-types/overrides.d.ts                 1      1      0
test/integration/bun-types/bun-types.test.ts      4      5      0

root cause · written by the author bot

The bug was that the memoryPressure overloads for removeListener and off in overrides.d.ts were the only declarations of those methods on the NodeJS.Process interface under @types/node@24, where Process inherits them solely from EventEmitter; since re-declared methods in a derived interface hide inherited overloads rather than merging with them, the memoryPressure signature became the only one visible, rejecting any other event name. The fix re-declares the generic (eventName: string | symbol, listener: (...args: any[]) => void) overload alongside the memoryPressure overloads, so both the t…

@coderabbitai

coderabbitai Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8fa31341-b8a3-4c0b-8821-5411e18e9191

📥 Commits

Reviewing files that changed from the base of the PR and between 3f78cd9 and 7e07e7a.

📒 Files selected for processing (2)
  • packages/bun-types/overrides.d.ts
  • test/integration/bun-types/bun-types.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 1 remains after this review.


Walkthrough

Changes

Process listener type compatibility

Layer / File(s) Summary
Process overloads and type validation
packages/bun-types/overrides.d.ts, test/integration/bun-types/bun-types.test.ts
Process.off and Process.removeListener now accept string or symbol events with variadic listeners. The integration test verifies generic events and typed memoryPressure handling with @types/node@24.

Suggested reviewers: alii

Merge Risk: ⚪ Minimal · up to 7e07e

This restores valid TypeScript calls to process.off and process.removeListener without changing runtime behavior. The regression coverage and full bun-types checks pass, so no actionable merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the primary change: preserving generic process.removeListener and off signatures with @types/node 24.
Description check ✅ Passed The description explains the problem, root cause, fix, compatibility considerations, and verification results. It does not use the exact template headings, but it provides the required information.

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

@robobun

robobun commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@robobun

robobun commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

LGTM — minimal types-only fix that re-declares the generic off/removeListener signatures so the memoryPressure overloads no longer hide the inherited ones under @types/node@24.

What was reviewed:

  • Confirmed the two added signatures match EventEmitter's exactly, so on @types/node@26 (which declares them on Process directly) the merge is a no-op — the existing base-fixture tests cover that path.
  • Checked the other augmented methods (on/once/addListener/prependListener/prependOnceListener/emit) are declared on Process by @types/node@24, so they don't need the same treatment.
  • The new test follows the existing Bun.mmap spawned-tsc pattern in the same file, pins the major, and asserts the installed @types/node version to guard against resolution drift making it vacuous.
Extended reasoning...

Overview

This PR fixes a TypeScript declaration-merging regression in packages/bun-types/overrides.d.ts. When bun-types augments NodeJS.Process with memoryPressure-specific overloads for off and removeListener, and the user has @types/node@24 installed (which only inherits those two methods from EventEmitter rather than declaring them on Process), the augmentation hides the inherited generic signatures — so process.removeListener("SIGINT", fn) fails to type-check. The fix re-declares the generic (event: string | symbol, listener: (...args: any[]) => void): this signatures alongside the specific ones. A new integration test in test/integration/bun-types/bun-types.test.ts pins @types/node@24 and runs tsc over calls that exercise both the generic and memoryPressure signatures.

Security risks

None. This is a pure .d.ts change with no runtime effect, plus a test addition.

Level of scrutiny

Low. The production change is two overload signatures plus an explanatory comment. The signatures are copied verbatim from EventEmitter, so on @types/node versions that already declare them on Process (26+), declaration merging adds an identical overload — harmless. The PR description correctly explains why only off and removeListener need this (the other event methods are declared directly on Process in @types/node@24, so bun-types' overloads merge with them rather than shadowing an inherited signature).

Other factors

The test is well-constructed: it follows the exact pattern of the neighboring Bun.mmap spawned-tsc check (writes a tsconfig + fixture into TEMP_DIR, copies the packed bun-types/@types/bun from BASE_FIXTURE_DIR, spawns tsc, drains stdout/stderr/exited concurrently via Promise.all, asserts output before exit code). It explicitly asserts @types/node's installed major is 24. so a future registry retag can't silently make the test vacuous, and it also asserts the memoryPressure overload's typed level parameter still works — i.e. the fix didn't lose the specific typing. The bun add @types/node@24 network call matches this file's existing convention (the same file already installs @typescript/native-preview, @types/react, etc. from the registry). No prior reviewer comments to address.

@robobun
robobun force-pushed the farm/bd2ca903/fix-process-removelistener-types branch from f0b736f to beea668 Compare August 23, 2026 05:23

@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 PR and didn't find any bugs. The two-line .d.ts fix is minimal and the root-cause analysis (derived-interface method declarations hiding inherited EventEmitter overloads under @types/node@24) checks out. Deferring for a human look since packages/bun-types/ has a CODEOWNER.

What was reviewed:

  • Confirmed the generic (event: string | symbol, ...) signatures match what EventEmitter provides, so the added overloads are a no-op merge on @types/node@26 and only restore the hidden signatures on 24.
  • Checked the other augmented event methods (on, once, addListener, prependListener, prependOnceListener, emit) — @types/node@24 declares those on Process directly, so they merge without hiding and need no matching change.
  • The new test pins @types/node@24, asserts the resolved major to guard against drift, and still exercises the typed memoryPressure listener; it follows the same spawned-tsc pattern as the neighbouring Bun.mmap check.
Extended reasoning...

Overview

This PR fixes a TypeScript declaration-merging regression in packages/bun-types/overrides.d.ts. The existing memoryPressure-specific overloads for off and removeListener on NodeJS.Process hid the generic signatures inherited from EventEmitter when used with @types/node@24, causing tsc to reject calls like process.removeListener("SIGINT", fn) (#40003). The fix re-declares the generic (event: string | symbol, listener: (...args: any[]) => void): this signatures alongside the specific overloads. A new integration test pins @types/node@24 and verifies both the generic event names and the typed memoryPressure listener type-check.

Security risks

None. This is a pure type-declaration change with no runtime code path affected. The test only spawns tsc over a fixture.

Level of scrutiny

Low-to-medium. The .d.ts change is two lines that mirror signatures already present on EventEmitter, so the effective API surface is unchanged — it just restores visibility of overloads that were being shadowed. The test is 53 lines and closely follows the existing Bun.mmap / TextDecoder spawned-tsc pattern in the same file, including the bun add from the registry (which this integration test file already does throughout). The PR description's mechanistic explanation of why only off/removeListener are affected (they alone are not re-declared on Process by @types/node@24) is correct and I verified the other five event methods do not need the same treatment.

Other factors

The gating factor for approval is that packages/bun-types/ is owned by a CODEOWNER in .github/CODEOWNERS, so per policy this should get a human sign-off even though the change itself is small and mechanically sound. The evidence block shows the new test fails on main with the exact reported TS2345 error and passes with the fix, and the full 16-test bun-types suite still passes on release. No prior human review comments to address.

@robobun

robobun commented Aug 23, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 2:15 AM PT - Aug 30th, 2026

✅ @robobun, your commit 25976ed8a0c9d403ae9f8becb2c717ae975230c3 passed in Build #108493! 🎉


🧪   To try this PR locally:

bunx bun-pr 40004

That installs a local version of the PR into your bun-40004 executable, so you can run:

bun-40004 --bun

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator

@robobun fix conflicts

…ible

The memoryPressure overloads declared on NodeJS.Process hide the
removeListener and off signatures inherited from EventEmitter when
@types/node does not declare them on Process directly (@types/node
<= 24). Re-declare the generic signatures next to the memoryPressure
overloads so any event name still typechecks.

Fixes #40003
@robobun

robobun commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased onto main and resolved the conflicts. Both were in test/integration/bun-types/bun-types.test.ts: main added the TextDecoder (#40119) and Event/EventTarget (#40574) blocks at the same insertion point as the new test, so I kept those blocks and moved the new test after them. The diff against main is unchanged (same 61 added lines). The full bun-types suite passes locally, 20/20.

@robobun
robobun force-pushed the farm/bd2ca903/fix-process-removelistener-types branch from beea668 to 7e07e7a Compare August 30, 2026 08:36

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

Code review found no issues

No high-confidence issues detected in this change.

@Jarred-Sumner
Jarred-Sumner merged commit 41906a4 into main Aug 30, 2026
8 checks passed
@Jarred-Sumner
Jarred-Sumner deleted the farm/bd2ca903/fix-process-removelistener-types branch August 30, 2026 10:03
7nohe added a commit to gurenjs/guren that referenced this pull request Sep 4, 2026
bun-types 1.4.1 restores the generic process.off signature that 1.4.0
shadowed with its memoryPressure overload (oven-sh/bun#40004), and the
root floor now sits at ^1.4.1, so the EventEmitter cast in
registerProcessTeardown has nothing left to work around. No runtime
change; typecheck and the Application lifecycle tests stay green.
7nohe added a commit to gurenjs/guren that referenced this pull request Sep 4, 2026
bun-types 1.4.1 restores the generic process.off signature that 1.4.0
shadowed with its memoryPressure overload (oven-sh/bun#40004), and the
root floor now sits at ^1.4.1, so the EventEmitter cast in
registerProcessTeardown has nothing left to work around. No runtime
change; typecheck and the Application lifecycle tests stay green.
7nohe added a commit to gurenjs/guren that referenced this pull request Sep 4, 2026
* ci: move the Bun trial lane and bun-types to 1.4.1

Bun 1.4.1 shipped today. The trial lane in ci.yml follows it, and the
root bun-types floor moves with it. Every other workflow keeps pinning
the primary version (1.3.14); scripts/workflow-bun-version.test.ts
enforces that and stays green. The lockfile was regenerated on 1.3.14
so the primary lane's --frozen-lockfile install is unchanged.

Verified on 1.4.1: bun install --frozen-lockfile, build:clean,
typecheck, test:bun (6495 pass / 0 fail), test:examples.

* refactor(server): drop the bun-types 1.4.0 process.off cast

bun-types 1.4.1 restores the generic process.off signature that 1.4.0
shadowed with its memoryPressure overload (oven-sh/bun#40004), and the
root floor now sits at ^1.4.1, so the EventEmitter cast in
registerProcessTeardown has nothing left to work around. No runtime
change; typecheck and the Application lifecycle tests stay green.
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.

2 participants