Skip to content

bun-types: declare memoryPressure in ProcessEventMap; fix and enforce the scripts/build typecheck - #37790

Closed
robobun wants to merge 3 commits into
mainfrom
farm/bf11a0c1/scripts-build-typecheck
Closed

robobun wants to merge 3 commits into
mainfrom
farm/bf11a0c1/scripts-build-typecheck

Conversation

@robobun

@robobun robobun commented Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • bunx tsc --noEmit -p scripts/build/tsconfig.json, the typecheck scripts/build/CLAUDE.md documents, exits 2 on main with 11 errors in files nobody is editing. Nothing in CI runs it, so it rotted.
  • Six are TS2345: Argument of type '"beforeExit"' is not assignable to parameter of type '"memoryPressure"' on plain process.once / process.off calls. They come from Add process.on('memoryPressure') event #32594, which declared the memoryPressure overloads of on/once/off/... directly on NodeJS.Process.
  • On the @types/node this repo pins (25.0.0) those declarations replace the inherited event methods, so "memoryPressure" is the only event they accept. On <= 24 only off/removeListener break; on 25.1+ nothing does, and that is what the bun-types fixture installs, so it never saw this.
  • The other five (TS2532, TS2769) are ordinary noUncheckedIndexedAccess misses in code added after the typecheck stopped being run.

Fix

  • memoryPressure becomes an entry in @types/node's ProcessEventMap (a declare module "node:process" augmentation) instead of redeclared methods. Both the inherited (25.0.x) and redeclared (25.1+) method sets key off that map, so every method types the event and Node's own events are untouched.
  • Trade-off: @types/node <= 24 has no event map, so there memoryPressure is only accepted where Process has an untyped fallback overload (on, once). bun-types has targeted @types/node 25 since @types/bun: Update to @types/node@25, fallback to PropertyKey in test expect matchers when keyof unknown is used #25460 and its other node:* augmentations degrade the same way.
  • The five build-script errors get ! assertions or an !== undefined check. The table lookups are in range for any byte, and the generated output is byte-identical.
  • Verification: a new source lint fails on any EventEmitter member declared on a Process merge in bun-types (eight hits on main, none here, on any @types/node), and a new test runs the scripts/build typecheck in CI (fails on main). The declaration was also typechecked against @types/node 25.0.0, 25.1.0 and 26.2.0.

Background

  • packages/bun-types is the published type package. It adds Bun's members to Node's NodeJS.Process by declaring interface Process { ... } again, which TypeScript merges with @types/node's declaration.
  • The merging rule this hinges on: a member declared in the merge sits next to overloads the base interface declares itself, but replaces one the base only inherits. So redeclaring on adds an overload or wipes the method depending on where @types/node put it, and that moved between 24, 25.0 and 25.1.
  • ProcessEventMap (@types/node 25) maps each process event name to its listener argument tuple; the event methods are generic over it, so one entry types an event on all of them.
  • noUncheckedIndexedAccess is the tsconfig option under which arr[i] is T | undefined, hence the ! assertions.
  • test/internal/source-lints/ runs on a bare checkout with nothing installed, so its lint is a text scan; test/internal/ has the root devDependencies, which tsc needs.
Original description

Problem

bunx tsc --noEmit -p scripts/build/tsconfig.json, the typecheck scripts/build/CLAUDE.md documents, exits 2 on main (9518091 and 626034f) with 11 errors in files nobody is editing. Nothing in CI runs it, so it rotted:

scripts/build/ci.ts(101,18): error TS2345: Argument of type '"beforeExit"' is not assignable to parameter of type '"memoryPressure"'.
scripts/build/ci.ts(102,18): error TS2345: Argument of type '"SIGINT"' is not assignable to parameter of type '"memoryPressure"'.
scripts/build/ci.ts(103,18): error TS2345: Argument of type '"SIGTERM"' is not assignable to parameter of type '"memoryPressure"'.
scripts/build/ci.ts(106,17): error TS2345: Argument of type '"beforeExit"' is not assignable to parameter of type '"memoryPressure"'.
scripts/build/ci.ts(107,17): error TS2345: Argument of type '"SIGINT"' is not assignable to parameter of type '"memoryPressure"'.
scripts/build/ci.ts(108,17): error TS2345: Argument of type '"SIGTERM"' is not assignable to parameter of type '"memoryPressure"'.
scripts/build/jsonByteClass.ts(17,40): error TS2532: Object is possibly 'undefined'.
scripts/build/jsonByteClass.ts(17,58): error TS2532: Object is possibly 'undefined'.
scripts/build/rust-lto-fix-cli.ts(141,66): error TS2769: No overload matches this call.
scripts/build/xmlByteClass.ts(19,40): error TS2532: Object is possibly 'undefined'.
scripts/build/xmlByteClass.ts(19,58): error TS2532: Object is possibly 'undefined'.

Cause

The six ci.ts errors are a bun-types bug, not a build-script one. #32594 added process.on("memoryPressure") by declaring on/once/off/addListener/removeListener/prependListener/prependOnceListener/emit overloads for that one event directly on NodeJS.Process in overrides.d.ts. Interface merging adds those next to overloads Process declares itself, but a member declared on the merged interface replaces anything Process only inherits, and what it inherits depends on the @types/node version:

@types/node where Process gets its event methods what the override did
<= 24 per-event overloads declared on Process, except off and removeListener, which come from EventEmitter process.off(...) and process.removeListener(...) only accept "memoryPressure"
25.0.x all inherited from InternalEventEmitter<ProcessEventMap> every event method only accepts "memoryPressure", process.on("exit", ...) included
25.1+ generic overloads keyed on ProcessEventMap, declared on Process again nothing; this is what the bun-types fixture tests against, since it installs latest

The repo pins @types/node 25.0.0 (root and test/ resolutions), so anything typechecked against packages/bun-types in this repo gets the middle row. The process.once/process.off calls in ci.ts are where the build project runs into it.

The other five errors are ordinary noUncheckedIndexedAccess misses in code added after the typecheck stopped being run.

Fix

  • overrides.d.ts: declare the event in @types/node's ProcessEventMap (a declare module "node:process" augmentation, like the file's other node:* augmentations) instead of redeclaring the methods. The inherited (25.0.x) and redeclared (25.1+) generic overloads both key off that map, so level is typed "warning" | "critical" on every method, process.ProcessEventMap["memoryPressure"] exists the same way it does for Node's events, and Node's own events are left alone. The JSDoc moves onto the map entry. Trade-off on @types/node <= 24, which has no event map: memoryPressure is only accepted where Process has an untyped fallback overload (on, once), whereas before it was typed on all eight methods but off/removeListener were broken for every other event. bun-types has targeted @types/node 25 since @types/bun: Update to @types/node@25, fallback to PropertyKey in test expect matchers when keyof unknown is used #25460 (the existing node:tls and node:fs/promises augmentations degrade the same way on 24), so this seems like the right side of the trade.
  • jsonByteClass.ts, xmlByteClass.ts: the nibble LUT lookups are in range for any byte; assert it with ! like the rest of scripts/build. Generated output is byte-identical.
  • rust-lto-fix-cli.ts: assert bitcode[0] !== undefined rather than bitcode.length > 0, which narrows the later use; same pattern main() already uses for argv.

Tests

  • test/internal/source-lints/bun-types-process-event-methods.test.ts is the durable guard for the bun-types rule. Whether a typecheck catches an event method redeclared on Process depends on which @types/node it loads (all of them on 25.0.x, only off/removeListener on <= 24, none on 25.1+, which is what the bun-types fixture installs), so instead the lint scans every interface Process merge in the published .d.ts files and fails on any EventEmitter member declared there. On main it reports the eight members from Add process.on('memoryPressure') event #32594 (overrides.d.ts:78: on, once, off, ...); it also checks its own scanner against a sample with nested object types, doc comments and string literals, and asserts it still finds the package's Process merges so it cannot pass vacuously. source-lints.yml now also runs on packages/bun-types/**.
  • test/internal/build-typecheck.test.ts runs the documented typecheck with the typescript pinned in the root package.json. On main it fails with the ci.ts errors above in the assertion output; with this change it passes. tsc runs under node (always present in CI, where the runner itself is node; locally the test skips without it or without the root devDependencies), since the same run under a debug bun takes minutes. It is in test/internal rather than test/internal/source-lints because it needs the root devDependencies installed, which that workflow deliberately does not do.
  • test/integration/bun-types/fixture/process.ts now asserts memoryPressure is an entry in process.ProcessEventMap and is typed on every method including listeners() (both fail against the old declarations on any @types/node), and exercises Node's own events on the methods that have at times been inherited, which matters whenever the current @types/node has such a shape.

Verification

  • The new overrides.d.ts typechecks a probe of Node events plus memoryPressure on every method, with skipLibCheck off, against @types/node 25.0.0, 25.1.0 and 26.2.0; the old one fails 25.0.0 as described above. The updated fixture typechecked against packages/bun-types with the repo's pinned 25.0.0: 19 errors with the old declaration, none with the new one.
  • bun test test/integration/bun-types/bun-types.test.ts with a release bun (fixture resolves @types/node 26.2.0): 14/14 pass.
  • bun test test/internal/source-lints/ as the workflow runs it: 85/85 pass; bun bd test test/internal/build-*.test.ts: pass; tsc -p packages/bun-types passes.

… typecheck clean and enforced

bun-types declared on()/once()/off()/... overloads for "memoryPressure"
directly on NodeJS.Process. Interface merging puts those next to the
members Process declares itself, but replaces anything Process only
inherits: on @types/node 25.0.x, where Process extends
InternalEventEmitter<ProcessEventMap>, that is every event method, so
process.on("exit", ...) and every signal stop typechecking; on
@types/node <= 24 it is off() and removeListener(), which Process
inherits from EventEmitter. The repo pins @types/node 25.0.0, which is
why `tsc -p scripts/build/tsconfig.json` failed on the process.once /
process.off calls in scripts/build/ci.ts.

Declare the event in @types/node's ProcessEventMap instead. The
inherited (25.0.x) and redeclared (25.1+) generic overloads both key
off that map, so the listener stays typed and Node's own events are
untouched.

Also fix the three remaining noUncheckedIndexedAccess errors in
jsonByteClass.ts, xmlByteClass.ts and rust-lto-fix-cli.ts, and add
test/internal/build-typecheck.test.ts, which runs the typecheck that
scripts/build/CLAUDE.md documents so it cannot silently rot again.
@robobun
robobun requested a review from alii as a code owner August 12, 2026 08:01
@robobun

robobun commented Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 1:05 PM PT - Aug 12th, 2026

❌ @robobun, your commit 01561c9 has some failures in Build #93310 (All Failures)


🧪   To try this PR locally:

bunx bun-pr 37790

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

bun-37790 --bun

@robobun

robobun commented Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status: reproduced on main with bunx tsc --noEmit -p scripts/build/tsconfig.json (exit 2, 11 errors; the 6 in ci.ts reproduce in any project that uses packages/bun-types with the repo's pinned @types/node 25.0.0). Fix and tests are in this PR: test/internal/build-typecheck.test.ts and test/internal/source-lints/bun-types-process-event-methods.test.ts both fail on main and pass here.

CI for the current head (01561c9, build 93310): all 179 jobs that ran passed, including both new tests on every lane, the bun-types workflow and source-lints. The build is marked failed only because the two darwin 26 aarch64 test shards expired without ever getting an agent; that is happening to every PR build right now (darwin 26 shards on all of the last ~40 PR builds are expired or waiting_failed) and has been reported separately. The earlier build (92998) had the same expired shards plus one unrelated grpc flake on darwin 14, also reported separately. Nothing left to do here from my side; ready for @alii's review of the bun-types change.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Bun types and build checks

Layer / File(s) Summary
Process event declaration contract
packages/bun-types/overrides.d.ts, test/integration/bun-types/fixture/process.ts
Moves memoryPressure to ProcessEventMap and adds type checks for process event callbacks, listeners, emission, and listener retrieval.
Process event declaration lint
test/internal/source-lints/bun-types-process-event-methods.test.ts, .github/workflows/source-lints.yml
Scans published declarations for direct EventEmitter members on NodeJS.Process and runs the source-lint workflow for bun-types changes.
Build script typecheck
scripts/build/*.ts, scripts/build/CLAUDE.md, test/internal/build-typecheck.test.ts
Adds a pinned TypeScript typecheck for build scripts and updates indexed-access checks to satisfy it.

Suggested reviewers: alii

🚥 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 summarizes the main bun-types declaration change and the scripts/build typecheck fixes.
Description check ✅ Passed The description explains the problem, implementation, testing, and verification in detail, despite not using the template headings exactly.

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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

@robobun

robobun commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 12, 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.

I reviewed this PR and didn't find any bugs. Since it changes the public shape of the memoryPressure declaration in packages/bun-types/overrides.d.ts (CODEOWNER-protected) and takes an explicit trade-off on @types/node ≤ 24, a human sign-off on the bun-types change would still be worthwhile.

What was reviewed

  • ProcessEventMap augmentation vs. the old per-method overloads — checked that the declare module "node:process" pattern matches the file's existing node:tls/node:fs/promises augmentations and that the JSDoc is preserved.
  • rust-lto-fix-cli.ts — bitcode[0] !== undefined is equivalent to bitcode.length > 0 here (array built from readdirSync().filter().map(), no sparse slots) and narrows the later bitcode[0] use.
  • jsonByteClass.ts/xmlByteClass.ts — LUT indices are b & 0xf and b >> 4 on a byte, always 0–15 into 16-element arrays; ! is safe and generated output is unchanged.
  • New build-typecheck.test.ts — drains pipes concurrently, await using, skipIf gated on local devDeps, prefers nodeExe() to keep debug/ASAN runtime flat.
Extended reasoning...

Overview

This PR fixes a rotted tsc --noEmit -p scripts/build/tsconfig.json typecheck (11 errors on main) and enforces it in CI. The root cause of six errors is a bun-types bug: #32594 declared on/once/off/etc. overloads for "memoryPressure" directly on NodeJS.Process, which under interface merging replaces (rather than augments) methods that Process only inherits — on @types/node 25.0.x that is every event method, so process.on("exit", ...) etc. reject. The fix moves the declaration into @types/node's ProcessEventMap via a declare module "node:process" augmentation. The remaining five errors are trivial noUncheckedIndexedAccess fixes in build scripts (two ! assertions on provably-in-range LUT lookups; one bitcode.length > 0 → bitcode[0] !== undefined to get type narrowing). A new test/internal/build-typecheck.test.ts runs the typecheck in CI, and the bun-types fixture is expanded to cover all EventEmitter methods for both Node events and memoryPressure.

Security risks

None. This is type-declaration and build-script tooling only; no runtime code paths, no untrusted input handling, no auth/crypto/permissions.

Level of scrutiny

The build-script changes are mechanical and zero-risk (non-null assertions on 0–15 indices into 16-element const arrays; an equivalent length check). The bun-types change is small but is a public API surface change to a published package with an acknowledged behavioral trade-off on @types/node ≤ 24 (where ProcessEventMap doesn't exist, memoryPressure falls through to the untyped on/once fallback overloads instead of being typed on all eight methods). The PR argues this is the right side of the trade since bun-types already targets @types/node 25 (#25460) and the old declaration was actively breaking off/removeListener on ≤ 24 anyway — that reasoning is sound, but it's a policy call the bun-types codeowner should confirm.

Other factors

  • packages/bun-types/ and *.d.ts are owned by a CODEOWNER per .github/CODEOWNERS, which by itself is reason to defer.
  • The new test follows repo conventions (harness helpers, concurrent pipe drain, await using, skipIf with a reason, combined-object assertion so failures show the tsc error list). It runs tsc under nodeExe() ?? bunExe() so debug/ASAN lanes don't pay a 10–100× penalty.
  • The fixture additions include exact-type assertions (expectType(...).is<...>()) that would fail against the old declarations even on latest @types/node (via ProcessEventMap["memoryPressure"] and listeners("memoryPressure")), so they guard the declaration shape and not just the pinned version.
  • I did not independently verify the augmentation against all three @types/node versions the PR lists (node_modules aren't installed in this checkout), but the mechanism described matches how TypeScript module augmentation and interface-vs-inherited-member merging work, and the file's other node:* augmentations use the same pattern.

@robobun

robobun commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

On the one point the review could not check itself, the @types/node matrix: each version was verified by installing it next to a copy of the new overrides.d.ts and typechecking a probe (Node events on every event method with exact listener types, memoryPressure on every method, skipLibCheck: false). 25.0.0, 25.1.0 and 26.2.0 are clean with the new declaration; with the old one 25.0.0 rejects every Node event and 22.x / 24.x reject process.off and process.removeListener for everything but memoryPressure (their Process declares on/once/addListener/emit/prepend*/listeners itself and inherits the other two). The repo's own pin is also covered directly: the updated fixture/process.ts typechecked against packages/bun-types with the pinned 25.0.0 has 19 errors with the old declaration (four of them on lines that were already in the fixture) and none with the new one.

Assigned to @alii for the bun-types sign-off since the trade-off on @types/node <= 24 is a policy call.

…ild typecheck under node only

Which @types/node version a typecheck loads decides whether redeclaring
an event method on Process is caught (25.0.x catches all of them, <= 24
only off/removeListener, 25.1+ none), so the rule is enforced by a
source lint over packages/bun-types instead of by whichever version the
repo or the fixture happens to resolve. The source-lints workflow now
also runs on bun-types changes.

The build typecheck falling back to the bun under test was dead code in
CI (the runner is node) and could not pass locally on a debug build,
where tsc takes minutes; it now skips without node like it already did
without the root devDependencies.

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/internal/build-typecheck.test.ts`:
- Line 31: Update the command arguments in the build typecheck test to pass an
absolute TypeScript project path by replacing the relative project argument with
join(repoRoot, "scripts", "build", "tsconfig.json"), while preserving the
existing tsc invocation.
🪄 Autofix

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

Review profile: ASSERTIVE

Plan: Pro

Run ID: 40e93020-d080-4743-97bc-0df0ba060e30

📥 Commits

Reviewing files that changed from the base of the PR and between 626034f and 01561c9.

📒 Files selected for processing (9)
  • .github/workflows/source-lints.yml
  • packages/bun-types/overrides.d.ts
  • scripts/build/CLAUDE.md
  • scripts/build/jsonByteClass.ts
  • scripts/build/rust-lto-fix-cli.ts
  • scripts/build/xmlByteClass.ts
  • test/integration/bun-types/fixture/process.ts
  • test/internal/build-typecheck.test.ts
  • test/internal/source-lints/bun-types-process-event-methods.test.ts

Comment thread test/internal/build-typecheck.test.ts

@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. Since it changes the published packages/bun-types declarations (CODEOWNER-gated) and the author already flagged the @types/node ≤ 24 trade-off as a policy call for alii, I'll leave the sign-off to them.

What was reviewed:

  • overrides.d.ts: confirmed the ProcessEventMap augmentation follows the file's existing declare module "node:*" pattern and the JSDoc moved intact.
  • rust-lto-fix-cli.ts / *ByteClass.ts: the ! and bitcode[0] !== undefined narrowing are behavior-preserving; generated LUT output is unchanged.
  • New source-lint: checked the brace/string blanker handles the nested-object-type and commented-overload cases its self-test covers, and that the vacuous-pass guard (merges.length > 0) is present.
  • build-typecheck.test.ts: skip gating on !isCI && (node === null || !existsSync(tsc)) matches the stated CI invariants; pipes drained concurrently.
Extended reasoning...

Overview

The PR fixes a rotted tsc --noEmit -p scripts/build/tsconfig.json typecheck (11 errors on main) and enforces it going forward. Six of the errors trace to a bun-types regression: #32594 declared per-method memoryPressure overloads directly on NodeJS.Process, which under interface-merging rules replaces inherited EventEmitter members rather than adding to them, and how much Process inherits varies by @types/node version. The fix moves the declaration to a ProcessEventMap augmentation inside declare module "node:process". The remaining five errors are trivial noUncheckedIndexedAccess fixes in build scripts. Two new tests enforce the typecheck in CI and structurally lint bun-types for the pattern that caused the regression; the bun-types fixture gains exact-type coverage for both Node's events and memoryPressure across all EventEmitter methods.

Security risks

None. This is type-declaration and build-tooling only; no runtime code paths, auth, crypto, or untrusted-input handling are touched.

Level of scrutiny

Medium. The build-script edits (! assertions on in-range LUT indices, bitcode[0] !== undefined narrowing) are mechanical and provably behavior-preserving. The overrides.d.ts change, however, is a user-facing API-surface change to a published package with an explicitly documented trade-off on @types/node ≤ 24 (memoryPressure loses typed addListener/prepend*/off there in exchange for un-breaking off/removeListener for every other event). The reasoning is sound and well-verified across the version matrix, but it is exactly the kind of compatibility policy decision the CODEOWNER should confirm.

Other factors

  • .github/CODEOWNERS assigns /packages/bun-types/ to alii, and the PR author explicitly requested their sign-off on the trade-off — approving over that would be inappropriate.
  • Test quality is high: the fixture uses expectType().is<> exact assertions, the source-lint has a self-test proving it sees the right members and ignores nested/commented ones plus a non-vacuous guard, and build-typecheck.test.ts runs tsc under node so debug/ASAN lanes stay fast. The workflow paths: addition ensures the new lint actually triggers on bun-types edits.
  • No prior claude[bot] review exists on this PR, so this is the first pass.

Jarred-Sumner pushed a commit that referenced this pull request Aug 30, 2026
…ible with @types/node 24 (#40004)

### 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"'` (#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
- `bun-types` augments `NodeJS.Process` in `overrides.d.ts` to type the
Bun-only `memoryPressure` event (#32594).
- TypeScript merges same-name interface declarations, so overloads added
to `Process` coexist with the ones `@types/node` declares there. Hiding
only happens for methods the base interface (`EventEmitter`) declares
and the derived interface (`Process`) does not.
- The existing bun-types fixture resolves `@types/node@latest`
(currently 26), which masks the bug. That is why #39807 was closed as
unreproducible. The new test pins major 24 and asserts the installed
major so resolution drift cannot make it vacuous.
- #37790 touches the same declarations with a `ProcessEventMap`
approach, bundled with unrelated scripts/build typecheck fixes. This PR
is the minimal fix for the reported break on the current `@types/node`
LTS.

<!-- robobun:evidence:begin -->

---

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

<details><summary>fails on main (without fix)</summary>

```console
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 (7e07e7a)

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)
```

</details>

<details><summary>passes on PR (with fix)</summary>

```console
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 (d578a8c)

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)
```

</details>

<details><summary>diff hotspot</summary>

```
packages/bun-types/overrides.d.ts            |  8 +++++
 test/integration/bun-types/bun-types.test.ts | 53 ++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)
```

</details>

**gate history** · 4 passed · 0 rejected · iteration 1

<details><summary>evidence per changed file</summary>

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

</details>

**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…

<!-- robobun:evidence:end -->
@robobun

robobun commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

The bun-types part of this change is now #41208 on its own, on top of #40004, which removed the conflict this branch has with main. That PR also drops the off/removeListener fallbacks that #40004 added: next to a ProcessEventMap entry they only hide the typed inherited signatures. If #41208 lands, a rebase here can drop the overrides.d.ts hunk and keep the scripts/build typecheck, the lint and the CI step.

@alii

alii commented Sep 3, 2026

Copy link
Copy Markdown
Member

this was fixed already i think?

@alii

alii commented Sep 3, 2026

Copy link
Copy Markdown
Member

shall we close this

@alii

alii commented Sep 3, 2026

Copy link
Copy Markdown
Member

@robobun

@robobun

robobun commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

Partly. I checked main at 1d1f431.

Fixed on main:

Not fixed on main:

  • The bun-types declaration. With @types/node 25.0.x, process.on("exit", ...) still fails to typecheck with TS2345: Argument of type '"exit"' is not assignable to parameter of type '"memoryPressure"'. bun-types: declare memoryPressure in ProcessEventMap, not as Process overloads #41208 fixes it. That PR is open and assigned to you.
  • bunx tsc --noEmit -p scripts/build/tsconfig.json still exits 2 with four TS2532 errors in jsonByteClass.ts and xmlByteClass.ts. No CI job runs this typecheck.

Yes, I am closing this PR. It conflicts with main, and #41208 has its bun-types part. If you want CI to enforce the scripts/build typecheck, mention me here. Then I will open a small PR with the two one-line fixes and the test from this branch.

@robobun robobun closed this Sep 3, 2026
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