refactor(tsc): drop redundant timer globals from Deno libs#34028
Conversation
Removes setTimeout, setInterval, clearTimeout, clearInterval, and console redeclarations from lib.deno.shared_globals.d.ts (lib.node already provides these with compatible signatures), and empties NODE_ONLY_GLOBALS. localStorage and sessionStorage move to TYPES_NODE_IGNORABLE_NAMES instead. First step toward dropping the TS fork's global-partitioning machinery.
The variadic timeoutArgs test used a zero-param function with arguments and 5 call-site args, relying on Deno's permissive setTimeout overload. lib.node's generic overload can't infer TArgs from a zero-param callback. The two .ignore'd string-callback tests documented removed runtime functionality.
Restore NODE_ONLY_GLOBALS for the names where Deno's lib still has a declaration. Emptying the list entirely turned out to require also fixing structural conflicts with @types/node/undici-types (MessageEventInit, RequestInit, ResponseInit, crypto, Performance*) that deserve their own design pass. This PR keeps only the changes that follow directly from removing setTimeout/setInterval/clearTimeout/ clearInterval/console from lib.deno.shared_globals.d.ts: their NODE_ONLY_GLOBALS entries go away because lib.node now provides them unambiguously.
…obals These names live in NODE_ONLY_GLOBALS so @types/node's declarations of them are segregated to a separate symbol table and never reach lookups from non-node-source files. But Deno's runtime exposes Buffer, setImmediate, clearImmediate as global values; segregating them means user code that references them type-checks as TS2304 even though it works at runtime. Remove these (plus BufferConstructor / BufferEncoding / \"buffer\") from the list so lib.node's declarations land in the shared global table.
Remove names from the segregation list where it provides no value: - __dirname, __filename: Deno declares neither and lib.node's declarations are not visible at top level anyway. - ErrorConstructor: interface declarations merge naturally across files via TS's standard rules. - Global: NodeJS.Global was removed from @types/node; this entry is a no-op. - queueMicrotask: Deno's lib has a function declaration; lib.node's declaration merges as an overload. Names that stay (Console, crypto, gc, localStorage, sessionStorage, RequestInit, ResponseInit) are kept because each has a real conflict or context-isolation purpose that needs design work to unwind: TS2403 on crypto, TS2430 on RequestInit/ResponseInit vs undici-types, worker- context isolation for localStorage/sessionStorage, --expose-gc opt-in for gc, and LSP completion-quality sensitivity for Console.
…obals Removing Deno's `declare var console: Console` broke users with minimal @types/node setups: Deno's shouldLoadNodeTypes logic skips the bundled lib.node when any @types/node is installed, and a test-fixture stub @types/node (used in uses_types_node_pkg) does not declare console. Restore the declaration and put console/Console back in NODE_ONLY_GLOBALS so segregation prevents the conflict with real @types/node installations. Also update tests that asserted the old segregation behavior: - compare_globals/main.ts: Buffer is now type-visible in globalThis (previously asserted absent). - node_prefix_missing: setImmediate/clearImmediate are now type-visible, so --unstable-node-globals check no longer errors. Drop the exitCode:1 from both check variants and clear the expected errors from node_globals_check.out.
fibibot
left a comment
There was a problem hiding this comment.
Lib.node provides setTimeout/setInterval/clearTimeout/clearInterval with NodeJS.Timeout return type, so dropping the Deno copies in lib.deno.shared_globals.d.ts is a real dedup, not just a textual move — the lib.node overloads are now the single source. The corresponding trim of NODE_ONLY_GLOBALS in cli/tsc/mod.rs is consistent: console/Console/crypto/localStorage/sessionStorage/RequestInit/ResponseInit/gc stay partitioned (Deno still declares those with different shapes), while the four timers, Buffer*, setImmediate/clearImmediate/queueMicrotask, __dirname/__filename, ErrorConstructor, Global drop out and are picked up from lib.node directly.
The node_globals_check.out flip from a 2-error fail to a clean pass is the visible win — setImmediate/clearImmediate type-check under --unstable-node-globals now, and the stale "TODO: type checking doesn't work properly … wait till Deno 3" line goes with them. compare_globals/main.ts is updated accordingly to assert Buffer is on globalThis. CI is fully green across all targets including wpt release linux-x86_64.
- nit: dropping
timeoutArgsfromtests/unit/timers_test.tsloses coverage for thesetTimeout(cb, ms, ...args)variadic form — @types/node's<TArgs extends any[]>overload supports it, so a one-line typed-callback version could keep the runtime assertion. The twoDeno.test.ignoreremovals are pure cleanup, fine.
lunadogbot
left a comment
There was a problem hiding this comment.
NODE_ONLY_GLOBALS isn't actually emptied — console, Console, crypto, gc, localStorage, RequestInit, ResponseInit, sessionStorage remain. And the body says localStorage/sessionStorage move into TYPES_NODE_IGNORABLE_NAMES, but that list is byte-identical to main. Title says "drop redundant timer/console globals" but only the four timer declarations come out — declare var console: Console; at lib.deno.shared_globals.d.ts:490 is kept. Worth aligning the description with what actually ships.
One code question: why drop timeoutArgs in tests/unit/timers_test.ts? Node's timers do pass extra args through to the callback at runtime, so removing the test loses coverage without an obvious reason. Dropping the two .ignore'd string-callback tests alongside it is fine — they were already disabled.
) ## Summary Fixes a type-check regression where importing `RequestInit`/`ResponseInit` from npm packages (e.g. `npm:ky`) caused TS2353 errors because the types degraded to `{}`. The `@types/node` declarations use a conditional pattern: ```ts type _RequestInit = typeof globalThis extends { onmessage: any } ? {} : import("undici-types").RequestInit; interface RequestInit extends _RequestInit {} ``` In Deno's TSC fork, `RequestInit`/`ResponseInit` lived in `NODE_ONLY_GLOBALS`, so npm code resolved them to this empty-interface version. As a result `body`, `signal`, `headers`, and `status` did not exist on the npm-side `RequestInit`/`ResponseInit`, producing errors like: ``` Object literal may only specify known properties, and 'body' does not exist in type 'Options'. ``` ### Changes - `cli/tsc/mod.rs`: move `RequestInit` and `ResponseInit` out of `NODE_ONLY_GLOBALS` and into `TYPES_NODE_IGNORABLE_NAMES`, so npm code resolves them to Deno's `lib.deno_fetch` interfaces (which already have the full Web Fetch shape). - `cli/tsc/dts/node/globals.d.cts`: drop the now-redundant `_RequestInit`/`_ResponseInit` conditional aliases and their `interface X extends _X {}` declarations from the built-in node globals. - `tests/registry/npm/@denotest/globals/1.0.0/index.d.ts`: add type-level regression assertions in an npm-package context, verifying that `body`, `signal`, `headers`, and `status` are present on `RequestInit`/`ResponseInit`. These run via the existing `tests/specs/npm/compare_globals` spec. Closes denoland/divybot#360. Closes #32682. ## Test plan - [ ] `cargo test specs::npm::compare_globals` passes (type assertions added to fixture). - [ ] `deno check` on the issue's `npm:ky` reproduction (`{ body: "hello" }` in `Options`) succeeds. - [ ] `deno check` on the `npm:@solid-primitives/timer` reproduction (`makeTimer(..., setTimeout)`) continues to succeed (already fixed in #34028 — verify no regression). Co-authored-by: divybot <divybot@users.noreply.github.com> Co-authored-by: Divy Srivastava <me@littledivy.com>
lib.node is now in the default lib chain since #33823, so this removes Deno-side declarations for setTimeout, setInterval, clearTimeout, and clearInterval from lib.deno.shared_globals.d.ts. lib.node already provides compatible timer declarations, and Deno timers already return NodeJS.Timeout.
The scope is intentionally narrower than removing the global-partitioning machinery entirely. NODE_ONLY_GLOBALS is trimmed to the entries that still need segregation or context-specific behavior: console/Console, crypto, gc, localStorage, sessionStorage, RequestInit, and ResponseInit. The console declaration stays in Deno libs because the bundled lib.node can be skipped when a project has its own @types/node installed.
This also lets Buffer, setImmediate, clearImmediate, and queueMicrotask flow through the shared global table instead of being hidden behind NODE_ONLY_GLOBALS, matching globals that Deno exposes at runtime. Tests are updated for the newly visible globals, and timer tests that depended on the removed Deno-specific overloads or unsupported string callbacks are removed.