Skip to content

refactor(tsc): drop redundant timer globals from Deno libs#34028

Merged
bartlomieju merged 6 commits into
mainfrom
refactor/lib-deno-dedup-globals
May 14, 2026
Merged

refactor(tsc): drop redundant timer globals from Deno libs#34028
bartlomieju merged 6 commits into
mainfrom
refactor/lib-deno-dedup-globals

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

@bartlomieju bartlomieju commented May 13, 2026

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.

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.
Copy link
Copy Markdown
Contributor

@fibibot fibibot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 timeoutArgs from tests/unit/timers_test.ts loses coverage for the setTimeout(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 two Deno.test.ignore removals are pure cleanup, fine.

Copy link
Copy Markdown
Contributor

@lunadogbot lunadogbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@bartlomieju bartlomieju changed the title refactor(tsc): drop redundant timer/console globals from Deno libs refactor(tsc): drop redundant timer globals from Deno libs May 14, 2026
@bartlomieju bartlomieju merged commit b064bab into main May 14, 2026
137 checks passed
@bartlomieju bartlomieju deleted the refactor/lib-deno-dedup-globals branch May 14, 2026 16:53
littledivy added a commit that referenced this pull request Jun 2, 2026
)

## 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants