workers-types declares Buffer and process as const, discarding the @types/node globals

Open Beginner friendly
#7,026 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
84/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
node.js, typescript

Research direction

Start at index.d.ts lines 486–487 and inspect how the global Buffer and process declarations interact with @types/node. Reproduce the issue with the listed package versions and tsconfig, then run tsc with both type packages enabled. Done means Node’s Buffer and process globals retain their normal typings and the reproduction type-checks cleanly.

Written by the indexing model from the issue text.

Description

@cloudflare/workers-types declares Buffer and process as const, which discards the @types/node globals in any project that uses both.

index.d.ts (lines 486–487 in 5.20260817.1):

declare const Buffer: any;
declare const process: any;

@types/node declares var Buffer: BufferConstructor inside declare global { … } in buffer.buffer.d.ts. A var merges across declaration files; a block-scoped const does not. The redeclaration discards the @types/node global block, and ordinary Node code stops type-checking.

Affected: any project listing both @cloudflare/workers-types and node in compilerOptions.types.

First affected version 5.20260807.2
Last clean version 5.20260804.1
Still present in 5.20260817.1 (current latest)

Bisected by unpacking each published tarball and grepping index.d.ts, so the boundary is exact rather than inferred from a changelog. Ten consecutive releases now carry it.

Reproduction

package.json@cloudflare/workers-types@5.20260817.1, @types/node@22.20.1, typescript@5.9.3.

tsconfig.json:

{
  "compilerOptions": {
    "types": ["node", "@cloudflare/workers-types"],
    "strict": true,
    "skipLibCheck": true,
    "noEmit": true
  },
  "include": ["src"]
}

src/index.ts:

import { randomBytes } from "node:crypto";
export const id = (): string => randomBytes(8).toString("hex");

tsc --noEmit:

src/index.ts(2,50): error TS2554: Expected 0 arguments, but got 1.

The real error, which skipLibCheck hides

With skipLibCheck: false TypeScript states the actual problem:

node_modules/@cloudflare/workers-types/index.d.ts(486,15): error TS2451: Cannot redeclare block-scoped variable 'Buffer'.
node_modules/@types/node/buffer.buffer.d.ts(356,19): error TS2451: Cannot redeclare block-scoped variable 'Buffer'.

skipLibCheck: true — the default in most templates, including Cloudflare's own — suppresses the TS2451 and leaves only the downstream TS2554. That is why this presents as a mystery about randomBytes rather than as a redeclaration. A type probe shows randomBytes(8).toString resolving to () => string, i.e. Uint8Array.prototype.toString, because the Buffer interface members in the discarded global block are gone.

Isolated

Each row run, not reasoned about:

change result
types order reversed still fails — ordering is irrelevant
types: ["node"] alone clean
pin 5.20260804.1 clean
declare constdeclare var on both lines clean
delete both lines clean
delete the process line only still fails — Buffer alone is the cause
delete the Buffer line only clean

process has the same collision, and it is silent

declare const process: any collides with @types/node's var process identically. It produces no error only because any absorbs every member access — so rather than failing, it silently degrades process from NodeJS.Process to any. Anyone with both type sets has lost that typing without being told.

Suggested fix

Declare them as var, which merges with @types/node rather than colliding with it:

declare var Buffer: any;
declare var process: any;

Or do not emit them at all — a Workers project that wants Buffer or process types installs @types/node and sets nodejs_compat, and gets the real declarations rather than any.

Prior art

cloudflare/workerd#1298"Transitive loading of @types/node breaks Request/Response (etc.) types" — is the same collision class pointing the other way: @types/node clobbering workers-types when Node began declaring its own Request/Response. This is the mirror image.


Found while pinning dependency floors ahead of a first release of a Workers framework built on workerd. Happy to open a PR with the constvar change if that is the preferred fix.

Dominant language
C++
Stars
8.8k
Forks
744
Avg merge
2d 12h
Merged PRs (30d)
205

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from cloudflare/workerd

All issues in cloudflare/workerd

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.