Skip to content

bun-types: declare memoryPressure in ProcessEventMap, not as Process overloads - #41208

Open
robobun wants to merge 1 commit into
mainfrom
robobun/0edd58d2/bun-types-process-event-map
Open

robobun wants to merge 1 commit into
mainfrom
robobun/0edd58d2/bun-types-process-event-map

Conversation

@robobun

@robobun robobun commented Sep 2, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Fix

  • Declare memoryPressure as an entry of ProcessEventMap through a declare module "node:process" augmentation, and remove the overloads and the fallbacks from the merge. Every event method on @types/node 25 and 26 keys off that map.
  • Trade-off for @alii: @types/node 24 has no event map, so memoryPressure is an unknown event name there. on/once/off/removeListener accept it untyped. emit/addListener/prepend* reject it. bun-types targets 25+.
  • Verified: test/integration/bun-types/bun-types.test.ts. One check pins @types/node@25.0.0 (17 errors on main). One type-checks the whole fixture against the repo's pin (the 4 errors above on main).

Background

Fixes #39807

Notes

Where @types/node declares the process event methods, and what the old overloads did there:

@types/node event methods old overloads on the merge
24.x per-event overloads on Process, off/removeListener inherited from EventEmitter off/removeListener reject every other event (#40003)
25.0.0 to 25.0.9 all inherited from InternalEventEmitter<ProcessEventMap> every method rejects every other event (#39807)
25.0.10+ generic overloads over ProcessEventMap on Process none hidden, but the #40004 fallbacks make off/removeListener listeners any

Probe: a file that calls each event method with a Node event and with memoryPressure, and fails if a listener argument is any (type NotAny<T> = 0 extends 1 & T ? never : T), checked with skipLibCheck: false against the packed bun-types and each of @types/node 25.0.0, 25.0.1, 25.0.9, 25.0.10, 25.1.0, 25.9.5, 26.4.1, with TypeScript 7.0.2 and 6.0.2. All clean with this change. Also checked process.ProcessEventMap["memoryPressure"], import type { ProcessEventMap } from "node:process", and listeners("memoryPressure") on each.

Overload order: bun-types' index.d.ts references node before overrides.d.ts, so @types/node's Process is the earlier declaration and the merge's overloads come first. Checked on main with types set to ["bun"], ["bun-types"], ["node", "bun"], ["node", "bun-types"] and ["bun-types", "node"]: process.off("exit", code => ...) is any in all of them on 25.0.10 and 26.4.1.

On @types/node 24.0.0 and 24.13.3 with the default skipLibCheck: true: Node events typed on every method, and the #40003 cases pass. With skipLibCheck: false, the augmentation adds one TS2671: Cannot augment module 'node:process' because it resolves to a non-module entity to the three errors the node:tls augmentation already produces there (ConnectionOptions, KeyObject, TLSSocket). #37790 asked for a CODEOWNER decision on this same trade-off and got no answer.

Alternative tried: re-declaring the (event: string | symbol, ...) fallbacks for the other six methods, like #40004 did for two. The merge's overloads come first, so every Node event listener becomes any on every @types/node release, including 26. Keeping the #40004 fallbacks next to the map entry has the same effect on off/removeListener.

Repo effect: tsc --noEmit -p scripts/build/tsconfig.json resolves the pinned @types/node 25.0.0 and reports three memoryPressure errors in scripts/build/ci.ts on main. With this change, none. Four unrelated noUncheckedIndexedAccess errors remain there. #37790 covers those, plus a source lint and a CI step for that typecheck.

The whole-fixture check overrides fixture/package.json#resolutions for @types/node, because that field otherwise wins over an explicit bun add @types/node@<pin>.

Suites: bun bd test test/integration/bun-types/bun-types.test.ts (9 pass, 14 skip on debug), the same file with a release build (23 pass), tsc -p packages/bun-types/tsconfig.json.


[human-review] gate passed · iteration 0 · 2 files touched

fails on main (without fix)
ASAN without fix: 1 failed, 14 skipped
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/pr_gate.xml" test/integration/bun-types/bun-types.test.ts
bun test v1.4.1 (a6c4cc276)

test/integration/bun-types/bun-types.test.ts:
(pass) @types/bun integration test > building and packing bun-types leaves packages/bun-types untouched [2.81ms]
(pass) @types/bun integration test > packed bun-types includes CLAUDE.md [9.94ms]
(skip) @types/bun integration test > basic type checks > checks without lib.dom.d.ts
(skip) @types/bun integration test > TypeScript latest > checks without lib.dom.d.ts
(skip) @types/bun integration test > TypeScript 7.1 > checks the fixture and import attributes through ts7.1/index.d.ts
(skip) @types/bun integration test > @types/node at the repo's pin > checks the fixture against the pinned @types/node
(pass) @types/bun integration test > Bun.mmap > MMapOptions accepts offset and size [734.31ms]
(pass) @types/bun integration test > TextDecoder > accepts the encoding labels the runtime supports [742.98ms]
(pass) @types/bun integration test > TextDecoder > the fixture label table matches the runtime [38.07ms]
(pass) @types/bun
... (truncated)

release without fix: 2 FAILED
bun test v1.4.1-canary.1 (a6c4cc276)

test/integration/bun-types/bun-types.test.ts:
(pass) @types/bun integration test > building and packing bun-types leaves packages/bun-types untouched [0.09ms]
(pass) @types/bun integration test > packed bun-types includes CLAUDE.md [0.19ms]
(pass) @types/bun integration test > basic type checks > checks without lib.dom.d.ts [3000.85ms]
(pass) @types/bun integration test > TypeScript latest > checks without lib.dom.d.ts [425.06ms]
(pass) @types/bun integration test > TypeScript 7.1 > checks the fixture and import attributes through ts7.1/index.d.ts [382.72ms]
427 |       });
428 | 
429 |       const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
430 | 
431 |       expect(stderr.trim()).toBe("");
432 |       expect(stdout.trim()).toBe("");
                                  ^
error: expect(received).toBe(expected)

- ""
+ "process.ts(4,12): error TS2345: Argument of type '"SIGINT"' is not assignable to parameter of type '"memoryPressure"'.
+ process.ts(8,12): error TS2345: Argument of type '"beforeExit"' is not assignable to parameter of type '"memoryPressure"'.
+ process.ts(1
... (truncated)
passes on PR (with fix)
ASAN with fix: 14 skipped
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/pr_gate.xml" test/integration/bun-types/bun-types.test.ts
bun test v1.4.1 (a6c4cc276)

test/integration/bun-types/bun-types.test.ts:
(pass) @types/bun integration test > building and packing bun-types leaves packages/bun-types untouched [2.56ms]
(pass) @types/bun integration test > packed bun-types includes CLAUDE.md [6.14ms]
(skip) @types/bun integration test > basic type checks > checks without lib.dom.d.ts
(skip) @types/bun integration test > TypeScript latest > checks without lib.dom.d.ts
(skip) @types/bun integration test > TypeScript 7.1 > checks the fixture and import attributes through ts7.1/index.d.ts
(skip) @types/bun integration test > @types/node at the repo's pin > checks the fixture against the pinned @types/node
(pass) @types/bun integration test > Bun.mmap > MMapOptions accepts offset and size [709.35ms]
(pass) @types/bun integration test > TextDecoder > accepts the encoding labels the runtime supports [692.16ms]
(pass) @types/bun integration test > TextDecoder > the fixture label table matches the runtime [37.70ms]
(pass) @types/bun
... (truncated)

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 636ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[0/4] cargo bun_runtime → libbun_runtime.a
�[1m�[92m   Compiling�[0m bun_runtime v0.0.0 (/workspace/bun/src/runtime)
�[1m�[92m    Finished�[0m `release` profile [optimized + debuginfo] target(s) in 4m 19s
[1/4] link bun-profile
[3/4] strip bun
[3/4] bun-profile --revision
1.4.1-canary.1+f55402ed5
[build] done
bun test v1.4.1-canary.1 (f55402ed5)

test/integration/bun-types/bun-types.test.ts:
(pass) @types/bun integration test > building and packing bun-types leaves packages/bun-types untouched [0.09ms]
(pass) @types/bun integration test > packed bun-types includes CLAUDE.md [0.29ms]
(pass) @types/bun integration test > basic type checks > checks without lib.dom.d.ts [2873.13ms]
(pass) @types/bun integration test > TypeScript latest > checks without lib.dom.d.ts [422.46ms]
(pass) @types/bun integration test > TypeScript 7.1 > checks the fixture and import attributes through ts7.1/index.d.ts [389.85ms]
(pass) @types/bun integration test > @types/node at the repo's pin > checks the fixture against the pinne
... (truncated)
diff hotspot
packages/bun-types/overrides.d.ts            |  53 +++++------
 test/integration/bun-types/bun-types.test.ts | 136 +++++++++++++++++++++++----
 2 files changed, 141 insertions(+), 48 deletions(-)

gate history · 1 passed · 0 rejected · iteration 0

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

…ss overloads

A method declared on the bun-types Process merge hides the one Process
inherits. On @types/node 25.0.0 through 25.0.9, Process inherits every
event method from InternalEventEmitter<ProcessEventMap>, so the
memoryPressure overloads rejected every other event name (#39807):

  error TS2345: Argument of type '"SIGINT"' is not assignable to
  parameter of type '"memoryPressure"'.

The off/removeListener fallbacks from #40004 merge ahead of the
@types/node overloads when bun-types is loaded through its index.d.ts
(the default `types: ["bun"]` and every other order tried), which made
those listener arguments `any` on 24, 25 and 26.

Declare memoryPressure as an entry of ProcessEventMap through a
node:process augmentation and remove the method declarations from the
merge. Every event method is typed on 25.0.0 through 26.x. On 24, which
has no event map, memoryPressure is an unknown event name.

Add two bun-types checks: one pinned to @types/node@25.0.0 for each
event method, and one that type-checks the whole fixture against the
@types/node the repo pins.

Fixes #39807
@robobun
robobun requested a review from alii as a code owner September 2, 2026 23:07
@robobun

robobun commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Status: reproduced by type-checking test/integration/bun-types/fixture/process.ts against the packed bun-types with @types/node 25.0.1 (4 errors, all TS2345 ... not assignable to parameter of type '"memoryPressure"') and with 25.0.10 (clean). The new checks in test/integration/bun-types/bun-types.test.ts fail on main the same way and pass with this change, on both the debug and the release build.

@coderabbitai

coderabbitai Bot commented Sep 2, 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: Essentials

Run ID: 9ba29d82-f280-44e2-b7bc-d43dfeb2b402

📥 Commits

Reviewing files that changed from the base of the PR and between d854084 and f55402e.

📒 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; 5 remain after this review.


Walkthrough

Changes

Process event types

Layer / File(s) Summary
Process event declaration update
packages/bun-types/overrides.d.ts
memoryPressure is added to ProcessEventMap with "warning" and "critical" payloads. Direct Process event overloads and generic listener redeclarations are removed.
Node version integration validation
test/integration/bun-types/bun-types.test.ts
Reusable checks validate the pinned @types/node version and process event signatures for Node 24 and Node 25.0.

Suggested reviewers: dylan-conway

Merge Risk: ⚪ Minimal · up to f5540

This localized type-declaration change is merge-ready after normal checks and review; no actionable merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes directly address issue #39807 by preventing memoryPressure declarations from hiding existing process-event typings while retaining memoryPressure support. Integration tests cover the repor…
Out of Scope Changes check ✅ Passed The declaration changes and integration tests are directly related to the linked issue and stated objectives. No unrelated code changes are identified.
Title check ✅ Passed The title clearly and concisely describes the primary change: moving the memoryPressure declaration to ProcessEventMap instead of Process overloads.
Description check ✅ Passed The description explains the problem, the fix, compatibility trade-offs, linked issue, and verification steps. It covers the template requirements, although it uses equivalent headings instead of the …
Full details: Linked Issues check

Explanation

The changes directly address issue #39807 by preventing memoryPressure declarations from hiding existing process-event typings while retaining memoryPressure support. Integration tests cover the reported failure and related overload behavior.

Full details: Description check

Explanation

The description explains the problem, the fix, compatibility trade-offs, linked issue, and verification steps. It covers the template requirements, although it uses equivalent headings instead of the exact template headings.


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

@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. Because packages/bun-types/ is CODEOWNER-owned and the change carries an explicit trade-off for @ types/node 24 users (emit/addListener/prepend* now reject "memoryPressure" there), a human sign-off on that trade-off is still worthwhile.

What was reviewed:

  • The ProcessEventMap augmentation shape — tuple entry matches how @ types/node 25+ maps event methods, and the JSDoc is preserved.
  • Removed overloads vs. the new augmentation — confirmed no other Bun-specific process event overloads remain on the merge that would still shadow inherited signatures.
  • New tests follow the file's existing pattern (spawned tsc, bun add @ types/node@<spec>, stdout/stderr asserted before exit code); the NotAny<T> guard correctly rejects the (...args: any[]) fallback.
Extended reasoning...

Overview

This PR touches two files: packages/bun-types/overrides.d.ts (removes eight memoryPressure method overloads and two generic fallbacks from the NodeJS.Process interface merge, replaces them with a declare module "node:process" augmentation adding memoryPressure: [level: "warning" | "critical"] to ProcessEventMap) and test/integration/bun-types/bun-types.test.ts (refactors the existing @ types/node@ 24 process-event check into a shared helper, adds a pinned @ types/node@ 25.0.0 check with a NotAny<T> guard covering all eight event methods, and adds a whole-fixture check against the repo's own package.json#resolutions pin). This is a pure type-declaration change with no runtime code affected.

Security risks

None. The change is entirely in ambient TypeScript declarations and test fixtures that spawn tsc in temp directories. No auth, crypto, filesystem, or network-facing runtime code is touched.

Level of scrutiny

Medium, driven by ownership rather than risk. The declaration change itself is small and mechanically sound — augmenting ProcessEventMap is the idiomatic way to add process events on @ types/node 25+, and removing the shadowing overloads fixes real reported breakage (#39807, #40003). However, /packages/bun-types/ and *.d.ts are CODEOWNER-gated to alii, and the PR description explicitly flags a behavioral regression for @ types/node 24 users (memoryPressure becomes an unknown event name — accepted untyped by on/once/off/removeListener but rejected by emit/addListener/prepend*) and notes a prior PR asked for a CODEOWNER call on this exact trade-off without receiving one. That is precisely the kind of API-surface decision the CODEOWNERS entry exists to gate.

Other factors

The new tests are well-constructed: the NotAny<T> guard ensures listener arguments are actually typed rather than falling through to the (...args: any[]) overload, the version-prefix assertion guards against resolution drift, and the repo-pin check catches the case where the fixture's latest resolution masks breakage on the version Bun itself uses. The tests use bun add @ types/node@<spec> which contacts the registry — that pattern was already present in this file before this PR (the pre-existing @ types/node@ 24 check did the same), so it is not a newly introduced hermeticity concern. The skipLibCheck: false TS2671 warning on @ types/node 24 mentioned in the PR notes is consistent with existing behavior of the node:tls augmentation in the same file.

@robobun

robobun commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 4:26 PM PT - Sep 2nd, 2026

✅ @robobun, your commit f55402ed5df391e902b7bf42c31e42e20859e95e passed in Build #109464! 🎉


🧪   To try this PR locally:

bunx bun-pr 41208

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

bun-41208 --bun

This branch has not been deployed

No deployments
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.

New memoryPressure event type signature deletes all type signatures for other process events

2 participants