Skip to content

build: no-undef is enabled on TypeScript files, silently masked by parserOptions.project #893

Description

@bpowers

Problem

eslint.config.shared.js spreads core ESLint's recommended rules into the base config for **/*.ts and **/*.tsx:

rules: {
  ...eslint.configs.recommended.rules,   // <-- this turns on `no-undef`
  ...tseslint.configs.recommended.rules,
  ...
}

That enables core no-undef on TypeScript files. Confirmed via eslint --print-config in src/core:

no-undef: [2, {"typeof": false}]

typescript-eslint explicitly recommends turning no-undef off for TS files: tsc already performs this check with full knowledge of the type system, and the ESLint rule produces false positives on type-only references.

The trap

no-undef currently reports nothing, so it looks harmless. It is silent only as an accident of an unrelated setting:

Setting parserOptions.project causes @typescript-eslint/parser to read lib out of the tsconfig and inject the corresponding DOM/ES globals into ESLint's scope analysis. Those injected globals are what keep no-undef quiet.

Verified:

  • Removing project from src/diagram produces 383 spurious no-undef errors.
  • Adding parserOptions.lib: ['es2020','dom','dom.iterable'] back makes the findings byte-identical to the project run.

So no-undef is load-bearing on parserOptions.project -- a setting that exists for type-aware linting, of which we currently enable exactly zero rules.

Why it matters

This is a landmine for the next person who tries to speed up linting. project is a ~30% wall-clock cost on src/diagram and buys nothing today, so dropping it is the obvious optimization -- and it detonates 383 bogus errors that have nothing to do with the change. The failure mode gives no hint that no-undef is the culprit or that lib is the fix.

The hand-maintained globals block in the shared config (window, document, Image, requestAnimationFrame, JSX, ...) is a symptom of the same confusion: it exists to placate no-undef, and it will never be complete.

Fix

Set 'no-undef': 'off' for TS/TSX files in eslint.config.shared.js. tsc already covers it.

Once no-undef is off, the bespoke globals list can likely be pruned too -- worth checking which of the remaining core rules (if any) actually consume it.

Components affected

  • eslint.config.shared.js
  • All consumers: src/{core,diagram,app,engine,server}/eslint.config.js, website/eslint.config.js

Discovery context

Identified during an audit of eslint.config.shared.js while migrating the repo to TypeScript 7.

Related

This is one of five defects found in the same audit of eslint.config.shared.js:

Activity

  1. added
    bugSomething isn't working
    hygieneToil, but its useful to get get too behind on it
    javascriptPull requests that update Javascript code
    on Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghygieneToil, but its useful to get get too behind on itjavascriptPull requests that update Javascript code

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions