Skip to content

TS2411 reported on properties declared in node_modules .d.ts files (e.g. @types/jsdom DOMWindow), where tsc 6.0 silently allows them #3490

@tomquist

Description

@tomquist

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixThis will not be worked on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions