-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Before You File a Proposal Please Confirm You Have Done The Following...
- I have searched for related issues and found none that match my proposal.
- I have searched the current rule list and found no rules that match my proposal.
- I have read the FAQ and my problem is not listed.
Relevant Package
typescript-eslint
My proposal is suitable for this project
- I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).
Description
Executive summary
ESLint 10 introduces a breaking change to scope management: scope managers must now implement an addGlobals(names: string[]) method.
This hook is invoked during source finalization to seed declared globals.
The current TypeScript scope manager in @typescript-eslint 8.49.x does not provide this method, which causes ESLint 10 to throw before any rules execute:
TypeError: scopeManager.addGlobals is not a function
at addDeclaredGlobals (.../eslint/lib/languages/js/source-code/source-code.js:221:15)
at SourceCode.finalize ...
As a result, TypeScript projects cannot run ESLint 10 at all, even with a trivial flat config.
The proposal is to implement addGlobals (or an equivalent compatibility shim) in the TypeScript scope manager to restore ESLint 10 compatibility.
This is a small, well-scoped change that unblocks early adopters, prevents downstream breakage, and aligns the TypeScript tooling ecosystem with ESLint’s new contract.
What the proposal does
-
Implements the new scope manager API surface required by ESLint 10
- Add an
addGlobals(names: string[])method to the TS scope manager used by@typescript-eslint/parser. - Ensure it creates global variables for the provided names and resolves references to them in the global scope.
- Add an
-
Removes a hard crash in the ESLint 10 execution path
- ESLint 10 calls
addGlobalsduringSourceCode.finalize().
Without the method, linting crashes before rules run.
- ESLint 10 calls
-
Keeps behavior consistent with ESLint 10’s built-in scope manager
- Aim for feature parity so rules and plugins see the symbol table they expect.
-
Provides a defensive shim
- For dual-support with ESLint < 10, the method can be a no-op when not invoked, preserving backward compatibility.
Why this is useful
-
Restores linting for TypeScript users on ESLLint 10
TypeScript projects cannot adopt ESLint 10 until this missing method is implemented. -
Prevents ecosystem breakage
Many tools depend on@typescript-eslint/parser; missing APIs cause all ESLint-10-based TypeScript stacks to fail at startup. -
Aligns with ESLint’s documented breaking change
ESLint 10 requiresaddGlobalsfor all scope managers. -
Improves developer experience and trust
Early adopters and CI pipelines expect compatibility with major ESLint releases. -
Keeps rule authors and plugin authors unblocked
A functioning scope graph is essential for custom rules and advanced analysis. -
Reduces support load
Avoids duplicate crash reports tied to the missing method.
Technical context and expected behavior
-
What ESLint 10 expects:
DuringSourceCode.finalize(), ESLint collects declared globals and calls:scopeManager.addGlobals(names: string[])
-
What’s missing:
The TypeScript scope manager (8.49.x) does not implement the method. -
Target behavior:
Mirror ESLint’s default semantics:- Create or ensure variables exist in the global scope.
- Resolve references to those globals.
- Avoid duplication or unintended shadowing (idempotent behavior).
Backward/forward compatibility
- Backward: ESLint < 10 never calls
addGlobals, so adding the method is safe and non-breaking. - Forward: Implementing now prevents breakage in future 10.x releases and stabilizes the ecosystem.
Scope of change
- Surface area: Only the TypeScript scope manager used by
@typescript-eslint/parser. - Risk: Low, if implemented to match ESLint’s semantics.
- Testing needs:
- Creating globals for provided names.
- Reference resolution correctness.
- No duplication or unexpected behavior.
Why this should be prioritized
- Hard blocker: ESLint 10 + TypeScript cannot run at all.
- Ecosystem impact: Very high—
@typescript-eslintis the standard parser for TS. - Clear fix: ESLint documents the required change; the implementation is straightforward.
- Reduces churn: Fixing now avoids multiple duplicate issues as ESLint 10 adoption increases.
Proposed acceptance criteria
addGlobals(names: string[])exists and matches ESLint 10’s expected behavior.- TypeScript projects can run
eslint@10end-to-end (no pre-rule crash). - Regression tests ensure global creation and reference resolution.
- Optional: method is idempotent and guards against repeated invocations.
Summary
This proposal adds ESLint 10’s required addGlobals hook to the @typescript-eslint scope manager.
It is a focused, low-risk update that:
- Unblocks TypeScript users on ESLint 10
- Aligns the parser with documented ESLint 10 requirements
- Eliminates a startup crash that currently prevents linting
- Reduces support burden and keeps the ecosystem stable
Implementing this ensures that the TypeScript ESLint toolchain remains compatible, reliable, and ready for ESLint 10 adoption.
Additional Info
Additional Technical Details
-
Crash context and stack:
The failure occurs before any rule evaluation, during ESLint’s source‑finalization step. ESLint 10 invokesaddDeclaredGlobalsinside
eslint/lib/languages/js/source-code/source-code.js(around line 221), which then attempts to callscopeManager.addGlobals.
Because the TypeScript scope manager (from@typescript-eslint/parser8.49.x) does not implement this method, the runtime throws:TypeError: scopeManager.addGlobals is not a functionStack traces consistently begin at
SourceCode.finalize, flow throughaddDeclaredGlobals, and abort the run.
No rules execute, and no diagnostics are emitted. -
Dependency setup and prior blockers:
Initially, the flat config requiredglobals, and ESLint 10 would fail earlier if the package was not installed.
Installingglobalsresolves the import issue—but the addGlobals crash remains, confirming that the only blocker is the missing method on the TS scope manager.
No custom rules or additional plugins beyond@typescript-eslintwere used in the repro. -
Reproduction fidelity:
The minimal repro uses:- a flat config,
- the TypeScript parser,
- a single TypeScript file (
const x: number = 1;).
parserOptions.projectwas set tofalseto avoid project lookup; the crash still occurs.
Providing atsconfigdoes not affect the behavior—the crash happens before project-related operations.The crash reproduces on:
- Node
20.19.0 - Node
25.2.1
Every run of:
npx eslint index.ts --max-warnings=0with
[email protected]and@typescript-eslint8.49.0fails identically. -
Regression confirmation:
Using the same config and file, ESLint 9.39.1 runs successfully and reports no errors.
This isolates the regression to ESLint 10’s updated scope‑manager contract and confirms that the TypeScript parser/plugin continue functioning correctly under ESLint 9. -
Alignment with ESLint 10 breaking changes:
ESLint 10’s release notes explicitly state that custom scope managers must implement:addGlobals(names: string[])
and are required to resolve references for declared globals.
The observed crash is exactly what occurs when that API is missing.
ImplementingaddGlobalsin the TS scope manager should eliminate the failure and restore intended behavior. -
Scope and risk considerations:
The required change is narrowly scoped to the TS scope manager implementation.
Expected behavior: create or ensure globals exist and resolve references appropriately.
A robust version should:- be idempotent,
- avoid duplication,
- work safely with ESLint 9.x (which never calls
addGlobals).
Tests should verify:
- globals are created,
- references resolve to the global scope,
- existing bindings are not shadowed or corrupted.
-
Downstream impact:
Since@typescript-eslint/parseris the de facto parser for nearly all TypeScript tooling (CLIs, build systems, editors, CI),
the absence ofaddGlobalsmeans every attempt to adopt ESLint 10 in TS codebases fails immediately.
Adding the method unblocks early adopters, reduces duplicate crash reports, and preserves confidence in the TS toolchain’s alignment with ESLint majors. -
Mitigation in the interim:
Projects may pin ESLint to9.39.1to avoid the crash, but the correct long‑term fix is implementingaddGlobalsin the TS scope manager to restore ESLint 10 compatibility.