Skip to content

Infer RegExp for regular expression literals under isolatedDeclarations - #65419

Open
Andrii Drok (andriidrok1) wants to merge 1 commit into
microsoft:mainfrom
andriidrok1:isolated-declarations-regexp
Open

Andrii Drok (andriidrok1) wants to merge 1 commit into
microsoft:mainfrom
andriidrok1:isolated-declarations-regexp

Conversation

@andriidrok1

Copy link
Copy Markdown

Fixes #58383

Problem

Under --isolatedDeclarations, a declaration initialized with a regular expression literal reports TS9010/TS9012/TS9013 even though the type can only ever be RegExp:

export const re = /ab+c/gi;
//           ~~ error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations.

typeFromExpression in the pseudochecker has cases for numeric, string, bigint and boolean literals but none for RegularExpressionLiteral, so it falls through to "needs inference". The checker itself always types the literal as the global RegExp (checkRegularExpressionLiteral).

Change

  • pseudochecker: a PseudoTypeKindRegExp kind (a singleton like PseudoTypeString) and a RegularExpressionLiteral case returning it. There are no regex literal types, so it is not wrapped in MaybeConstLocation: the result is RegExp in const contexts too.
  • pseudotypenodebuilder: the new kind serializes as typeToTypeNode(globalRegExpType) and maps to globalRegExpType in pseudoTypeToType.

Serializing the global type instead of a hand-made RegExp identifier is what handles the shadowing concern raised in the issue: when a file declares its own RegExp, the node builder emits globalThis.RegExp, the same way declaration emit already refers to any shadowed global. That stays syntactically determinable for isolated tools, since the shadowing declaration or import is in the same file.

Notes

  • With noLib, globalRegExpType is the empty object type, so the emitted type is {}, the same as non-isolated declaration emit in that configuration.
  • This only changes the Go compiler; the 5.x (strada) line is unaffected.

Tests

isolatedDeclarationsRegExp.ts covers const/let/var, object literal properties, an as const object with a regex array, a function and an arrow return, class fields (including an optional one), parameter defaults followed by a required parameter, and two files that shadow RegExp (a class and a type alias). Output:

export declare const re: RegExp;
export declare const constObj: {
    readonly pattern: RegExp;
    readonly list: readonly [RegExp, RegExp];
};
export declare function withDefault(pattern: RegExp | undefined, flags: string): void;
// shadowed.d.ts
declare class RegExp { exec(): void; }
export declare const local: RegExp;
export declare const global: globalThis.RegExp;
// typeShadowed.d.ts
type RegExp = string;
export declare const globalType: globalThis.RegExp;

Without the change the same test reports 17 isolatedDeclarations errors (TS9010, TS9012, TS9013, TS9025) and no declarations for those initializers. No other baselines change. npx hereby test, lint, check:format and tidy pass with no diff.

I used Claude Code to draft this change; I reviewed and tested every line and will handle review feedback myself.

🤖 Generated with Claude Code

…tions`

The pseudochecker had no case for regular expression literals, so a
declaration like `export const re = /ab+c/g` reported TS9010 under
`--isolatedDeclarations` even though its type can only be the global
`RegExp`.

Add a `PseudoTypeKindRegExp` pseudotype returned for regex literals and
serialize it through the checker's `globalRegExpType`, so a file that
shadows `RegExp` still gets a correct `globalThis.RegExp` reference.

Fixes microsoft#58383

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 10, 2026 03:00
@typescript-automation typescript-automation Bot added the For Backlog Bug PRs that fix a backlog bug label Nov 10, 2026
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Nov 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified for the regular-expression inference change.

No open issues 🎉

What changed in this PR

Addresses #58383 by allowing the native TypeScript compiler to infer RegExp from regular expression literals under --isolatedDeclarations, including when a local declaration shadows RegExp.

Changes:

  • Adds a dedicated regular-expression pseudo-type and literal inference case.
  • Maps the pseudo-type to the global RegExp type for declaration emit.
  • Adds regression coverage and baselines for declarations, const contexts, returns, defaults, and shadowing.
File Description
tsc/​testdata/​tests/​cases/​compiler/​isolatedDeclarationsRegExp.ts Adds regression cases for regex inference and shadowing.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsRegExp.types Records expected inferred types.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsRegExp.symbols Records expected symbol bindings.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsRegExp.js Records JavaScript and declaration output.
tsc/​internal/​pseudochecker/​type.go Defines the RegExp pseudo-type kind and singleton.
tsc/​internal/​pseudochecker/​lookup.go Recognizes regular expression literals during inference.
tsc/​internal/​checker/​pseudotypenodebuilder.go Converts the pseudo-type using the global RegExp type.

Review effort: Balanced

@andriidrok1

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@jakebailey

Copy link
Copy Markdown
Member

I'm not sure why this issue was marked "help wanted"; this issue still requires discussion and has future implications

@andriidrok1

Copy link
Copy Markdown
Author

Understood. For context, the inference here is the one discussed in #58383: a plain RegExp, with no assumptions about future typed regex literals (#32098). If the team decides ID should not infer this at all, I'm fine with closing; if it's just the typing shape that's open, I'm happy to adjust once that's settled.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

[ID] --isolatedDeclarations disallows const initialized with a regex literal

3 participants