Steps to reproduce
mkdir jsdom-repro && cd jsdom-repro
npm init -y
npm i -D @types/jsdom@27 @typescript/native-preview@beta typescript@6.0.3 @types/node
tsconfig.json:
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022", "DOM"],
"noEmit": true,
"skipLibCheck": false,
"types": ["node"]
}
}
index.ts:
import type { JSDOM } from "jsdom";
declare const x: JSDOM;
console.log(x.window);
Tested with @typescript/native-preview@beta (Version 7.0.0-dev.20260421.2) and typescript@6.0.3.
@types/jsdom@27.0.0's DOMWindow interface declares:
interface DOMWindow extends Omit<Window, "top" | "self" | "window"> {
[key: string]: any;
// …
readonly ["Infinity"]: number;
readonly ["NaN"]: number;
readonly undefined: undefined;
// …
}
Window (from lib.dom.d.ts) has [index: number]: Window. Numeric-string literal property names like "Infinity" are checked against the numeric index signature, and number is not assignable to Window.
Behavior with typescript@6.0
Compiles cleanly (exit 0, no diagnostics) — tsc does not flag the conflict between readonly ["Infinity"]: number and the inherited [index: number]: Window on declarations inside node_modules.
Behavior with tsgo
node_modules/@types/jsdom/base.d.ts(205,18): error TS2411: Property '["Infinity"]' of type 'number' is not assignable to 'number' index type 'Window'.
node_modules/@types/jsdom/base.d.ts(206,18): error TS2411: Property '["NaN"]' of type 'number' is not assignable to 'number' index type 'Window'.
Both errors point inside node_modules. Adding --skipLibCheck makes tsgo pass.
A minimal hand-written reproduction (no @types/jsdom, just the same shape inline) errors under both tsc and tsgo:
interface MyDOMWindow extends Omit<Window, "top" | "self" | "window"> {
[key: string]: any;
readonly top: MyDOMWindow;
readonly self: MyDOMWindow;
readonly window: MyDOMWindow;
readonly ["Infinity"]: number;
readonly ["NaN"]: number;
}
So the divergence is about how each compiler treats this kind of declaration when it lives inside node_modules/@types/* rather than the source code itself. tsc 6.0 effectively suppresses the check for declarations inside node_modules; tsgo does not. Either choice is defensible, but the difference makes it impossible to use @types/jsdom under tsgo without --skipLibCheck or a yarn patch.
Steps to reproduce
tsconfig.json:{ "compilerOptions": { "strict": true, "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "lib": ["ES2022", "DOM"], "noEmit": true, "skipLibCheck": false, "types": ["node"] } }index.ts:Tested with
@typescript/native-preview@beta(Version 7.0.0-dev.20260421.2) andtypescript@6.0.3.@types/jsdom@27.0.0'sDOMWindowinterface declares:Window(fromlib.dom.d.ts) has[index: number]: Window. Numeric-string literal property names like"Infinity"are checked against the numeric index signature, andnumberis not assignable toWindow.Behavior with
typescript@6.0Compiles cleanly (exit 0, no diagnostics) — tsc does not flag the conflict between
readonly ["Infinity"]: numberand the inherited[index: number]: Windowon declarations insidenode_modules.Behavior with
tsgoBoth errors point inside
node_modules. Adding--skipLibCheckmakes tsgo pass.A minimal hand-written reproduction (no
@types/jsdom, just the same shape inline) errors under both tsc and tsgo:So the divergence is about how each compiler treats this kind of declaration when it lives inside
node_modules/@types/*rather than the source code itself. tsc 6.0 effectively suppresses the check for declarations insidenode_modules; tsgo does not. Either choice is defensible, but the difference makes it impossible to use@types/jsdomunder tsgo without--skipLibCheckor a yarn patch.