From 94fb8e6e19512dd0a2904078cbd0ac40e95affdb Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sun, 3 May 2026 02:14:14 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor(compat-eslint):=20KnownEstreeType?= =?UTF-8?q?=20union=20=E2=80=94=20compile-time=20phantom=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces a `KnownEstreeType` string-literal union listing every ESTree type lazy-estree is allowed to produce (~135 entries: core ESTree + JSX + TS-prefixed types + 13 TS keyword types). Used to constrain three places: - `LazyNode.type` (abstract): every concrete subclass's `type` literal must be in the union or compilation fails. - `defineShape({ type, ... })`: same for factory-built shapes. - `TypeKeywordNode` constructor parameter narrowed from `string` to a 13-entry `TypeKeyword` subset so the dynamic dispatch can't accept a non-keyword name. When the gate was added it caught one missing entry (`AccessorProperty` on PropertyDefinitionNode's union) on first build — exactly the bug class this gate exists to prevent. Added it to the union; build clean. Closes the bug class from PR #88 at the type level: the phantom `'TSJsxAttributes'` regression that started this whole refactor would now be a compile error, not a silent silent-replay-stale bug that needs a parity test to catch. Runtime phantom-types invariant (in lazy-estree.test) still backs this up for GenericTSNode's deliberate dynamic-output escape valve, which has to use `as` to satisfy the constraint and is exhausted by the parity sweep. Adding a new ESTree shape now requires editing `KnownEstreeType` first — explicit declaration, single source of truth. All compat-eslint suites still pass: 152/152 predicate coverage, 24/24 scope-compat, full bottom-up parity sweep + phantom-types invariant. Self-lint clean across 6 packages. --- packages/compat-eslint/lib/lazy-estree.ts | 113 ++++++++++++++++++++-- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/packages/compat-eslint/lib/lazy-estree.ts b/packages/compat-eslint/lib/lazy-estree.ts index d792bb2..8562514 100644 --- a/packages/compat-eslint/lib/lazy-estree.ts +++ b/packages/compat-eslint/lib/lazy-estree.ts @@ -111,6 +111,84 @@ export interface ConvertContext { // Frozen so callers can't mutate the shared instance. const EMPTY_ARRAY: never[] = Object.freeze([]) as never[]; +// Architectural gate: every ESTree type lazy-estree can produce must be +// listed here. Both `LazyNode.type` (hand-written subclasses) and +// `defineShape.type` (factory-built shapes) are constrained to this +// union — adding a new ESTree shape requires editing this list first. +// +// Why: prevents phantom types like 'TSJsxAttributes' (the bug class +// that started this refactor) from being introduced. Any subclass +// declaring `readonly type = 'X' as const` for an X not in this +// union fails at compile time. +// +// The union mirrors typescript-estree's published TS- and ES-prefixed +// node types. 13 TS keyword types (TSAnyKeyword, TSStringKeyword, …) +// are dynamic via TypeKeywordNode, so they go in here too. +type KnownEstreeType = + // Core ESTree + | 'AccessorProperty' | 'ArrayExpression' | 'ArrayPattern' + | 'ArrowFunctionExpression' + | 'AssignmentExpression' | 'AssignmentPattern' | 'AwaitExpression' + | 'BinaryExpression' | 'BlockStatement' | 'BreakStatement' + | 'CallExpression' | 'CatchClause' | 'ChainExpression' + | 'ClassBody' | 'ClassDeclaration' | 'ClassExpression' + | 'ConditionalExpression' | 'ContinueStatement' | 'DebuggerStatement' + | 'Decorator' | 'DoWhileStatement' | 'EmptyStatement' + | 'ExportAllDeclaration' | 'ExportDefaultDeclaration' + | 'ExportNamedDeclaration' | 'ExportSpecifier' | 'ExpressionStatement' + | 'ForInStatement' | 'ForOfStatement' | 'ForStatement' + | 'FunctionDeclaration' | 'FunctionExpression' | 'Identifier' + | 'IfStatement' | 'ImportAttribute' | 'ImportDeclaration' + | 'ImportDefaultSpecifier' | 'ImportExpression' | 'ImportNamespaceSpecifier' + | 'ImportSpecifier' | 'LabeledStatement' | 'Literal' + | 'LogicalExpression' | 'MemberExpression' | 'MetaProperty' + | 'MethodDefinition' | 'NewExpression' | 'ObjectExpression' + | 'ObjectPattern' | 'PrivateIdentifier' | 'Program' | 'Property' + | 'PropertyDefinition' | 'RestElement' | 'ReturnStatement' + | 'SequenceExpression' | 'SpreadElement' | 'StaticBlock' + | 'Super' | 'SwitchCase' | 'SwitchStatement' + | 'TaggedTemplateExpression' | 'TemplateElement' | 'TemplateLiteral' + | 'ThisExpression' | 'ThrowStatement' | 'TryStatement' + | 'UnaryExpression' | 'UpdateExpression' | 'VariableDeclaration' + | 'VariableDeclarator' | 'WhileStatement' | 'WithStatement' + | 'YieldExpression' + // JSX + | 'JSXAttribute' | 'JSXClosingElement' | 'JSXClosingFragment' + | 'JSXElement' | 'JSXEmptyExpression' | 'JSXExpressionContainer' + | 'JSXFragment' | 'JSXIdentifier' | 'JSXMemberExpression' + | 'JSXNamespacedName' | 'JSXOpeningElement' | 'JSXOpeningFragment' + | 'JSXSpreadAttribute' | 'JSXSpreadChild' | 'JSXText' + // TS-specific (composite types) + | 'TSAbstractAccessorProperty' | 'TSAbstractKeyword' + | 'TSAbstractMethodDefinition' | 'TSAbstractPropertyDefinition' + | 'TSArrayType' | 'TSAsExpression' | 'TSCallSignatureDeclaration' + | 'TSClassImplements' | 'TSConditionalType' + | 'TSConstructSignatureDeclaration' | 'TSConstructorType' + | 'TSDeclareFunction' | 'TSEmptyBodyFunctionExpression' + | 'TSEnumBody' | 'TSEnumDeclaration' | 'TSEnumMember' + | 'TSExportAssignment' | 'TSExternalModuleReference' + | 'TSFunctionType' | 'TSImportEqualsDeclaration' | 'TSImportType' + | 'TSIndexSignature' | 'TSIndexedAccessType' | 'TSInferType' + | 'TSInstantiationExpression' | 'TSInterfaceBody' + | 'TSInterfaceDeclaration' | 'TSInterfaceHeritage' + | 'TSIntersectionType' | 'TSLiteralType' | 'TSMappedType' + | 'TSMethodSignature' | 'TSModuleBlock' | 'TSModuleDeclaration' + | 'TSNamedTupleMember' | 'TSNamespaceExportDeclaration' + | 'TSNonNullExpression' | 'TSOptionalType' | 'TSParameterProperty' + | 'TSPropertySignature' | 'TSQualifiedName' | 'TSRestType' + | 'TSSatisfiesExpression' | 'TSTemplateLiteralType' | 'TSThisType' + | 'TSTupleType' | 'TSTypeAliasDeclaration' | 'TSTypeAnnotation' + | 'TSTypeAssertion' | 'TSTypeLiteral' | 'TSTypeOperator' + | 'TSTypeParameter' | 'TSTypeParameterDeclaration' + | 'TSTypeParameterInstantiation' | 'TSTypePredicate' | 'TSTypeQuery' + | 'TSTypeReference' | 'TSUnionType' + // TS keyword types (TypeKeywordNode dynamic dispatch) + | 'TSAnyKeyword' | 'TSBigIntKeyword' | 'TSBooleanKeyword' + | 'TSIntrinsicKeyword' | 'TSNeverKeyword' | 'TSNullKeyword' + | 'TSNumberKeyword' | 'TSObjectKeyword' | 'TSStringKeyword' + | 'TSSymbolKeyword' | 'TSUndefinedKeyword' | 'TSUnknownKeyword' + | 'TSVoidKeyword'; + function getLocFor(ast: ts.SourceFile, start: number, end: number) { const startLC = ast.getLineAndCharacterOfPosition(start); const endLC = ast.getLineAndCharacterOfPosition(end); @@ -121,7 +199,11 @@ function getLocFor(ast: ts.SourceFile, start: number, end: number) { } abstract class LazyNode { - abstract readonly type: string; + // Architectural gate: every concrete LazyNode subclass's `type` must + // be a member of KnownEstreeType. Prevents introducing phantom types + // like 'TSJsxAttributes' that don't exist in typescript-estree's + // shape. New ESTree shape = add to KnownEstreeType first. + abstract readonly type: KnownEstreeType; parent: LazyNode | null; _ts: ts.Node; // Conversion context shared with descendants. Children created via getter @@ -1237,7 +1319,7 @@ interface ShapeSlotDef { // annotations are undefined when absent). const SHAPE_UNSET = Symbol('shape-unset'); interface ShapeDef { - type: string; + type: KnownEstreeType; slots: Record>; // Static field defaults — values that don't depend on the TS node // (e.g. UnaryExpression's `operator: 'void'`, ObjectPattern's @@ -1941,7 +2023,17 @@ function convertChildren(children: ReadonlyArray, parent: LazyNode): (L // skip dispatching enter/leave on it. export const GENERIC_TS_NODE_MARKER: unique symbol = Symbol('GenericTSNode'); class GenericTSNode extends LazyNode { - readonly type: string; + // Type is dynamic: 'TS' + ts.SyntaxKind[kind]. Most produced types + // (e.g. 'TSEnumDeclaration', 'TSImportType') are valid KnownEstreeType + // members; some are NOT (e.g. 'TSJsxAttributes', 'TSEndOfFileToken') + // and represent the "synthetic fallback" for kinds that don't have + // a real ESTree counterpart. The phantom-types invariant test in + // lazy-estree.test asserts these never reach a position rules can + // observe — they exist only as transient objects on the bottom-up + // walk before being shadowed by a real subclass. Cast the field + // type to KnownEstreeType to satisfy the LazyNode constraint; the + // runtime invariant is the actual gate. + readonly type: KnownEstreeType; readonly [GENERIC_TS_NODE_MARKER] = true; constructor(tsNode: ts.Node, parent: LazyNode | null, context?: ConvertContext) { // Synthetic — don't claim the TS node's slot in the maps if a @@ -1955,7 +2047,7 @@ class GenericTSNode extends LazyNode { // _ctx from) — happens when materialize() bottom-up exhausts the TS // parent chain without hitting a cached ancestor. super(tsNode, parent, context); - this.type = 'TS' + ts.SyntaxKind[tsNode.kind]; + this.type = ('TS' + ts.SyntaxKind[tsNode.kind]) as KnownEstreeType; } } @@ -2265,9 +2357,18 @@ class TSTypeAnnotationNode extends LazyNode { // Type-position keywords (`any`, `number`, `string`, …). All have the same // shape — just `type: 'TSXxxKeyword'`. Group them under one class to avoid // 14 near-identical declarations. +// Type-keyword union — narrowed from KnownEstreeType to the keyword +// subset so the constructor's `type` parameter can't accept a +// non-keyword name by mistake. +type TypeKeyword = + | 'TSAnyKeyword' | 'TSBigIntKeyword' | 'TSBooleanKeyword' + | 'TSIntrinsicKeyword' | 'TSNeverKeyword' | 'TSNullKeyword' + | 'TSNumberKeyword' | 'TSObjectKeyword' | 'TSStringKeyword' + | 'TSSymbolKeyword' | 'TSUndefinedKeyword' | 'TSUnknownKeyword' + | 'TSVoidKeyword'; class TypeKeywordNode extends LazyNode { - readonly type: string; - constructor(type: string, tsNode: ts.Node, parent: LazyNode) { + readonly type: TypeKeyword; + constructor(type: TypeKeyword, tsNode: ts.Node, parent: LazyNode) { super(tsNode, parent); this.type = type; } From e31cbed058387664e5e69e96e64ab43202920c11 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sun, 3 May 2026 02:21:08 +0800 Subject: [PATCH 2/3] test(compat-eslint): pull AST_NODE_TYPES from upstream + comment fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses PR #90 review. Phantom-types invariant (lazy-estree.test): the hand-coded set of ~80 typescript-estree TS-* types is now derived from `@typescript-eslint/typescript-estree`'s exported `AST_NODE_TYPES` enum. When upstream adds a new type, the test auto-picks it up with no maintenance — and conversely, if our KnownEstreeType ever drifts to include a non-existent name, fixture runs catch it (any produced 'TS' not in the enum is flagged as phantom). Drops 80 lines of hand-listed strings from the test file. Also: comment on TypeKeywordNode said "14 near-identical declarations" — there are 13 keyword types. Off by one. --- packages/compat-eslint/lib/lazy-estree.ts | 2 +- .../compat-eslint/test/lazy-estree.test.ts | 96 ++----------------- 2 files changed, 10 insertions(+), 88 deletions(-) diff --git a/packages/compat-eslint/lib/lazy-estree.ts b/packages/compat-eslint/lib/lazy-estree.ts index 8562514..5e5e5ba 100644 --- a/packages/compat-eslint/lib/lazy-estree.ts +++ b/packages/compat-eslint/lib/lazy-estree.ts @@ -2356,7 +2356,7 @@ class TSTypeAnnotationNode extends LazyNode { // Type-position keywords (`any`, `number`, `string`, …). All have the same // shape — just `type: 'TSXxxKeyword'`. Group them under one class to avoid -// 14 near-identical declarations. +// 13 near-identical declarations. // Type-keyword union — narrowed from KnownEstreeType to the keyword // subset so the constructor's `type` parameter can't accept a // non-keyword name by mistake. diff --git a/packages/compat-eslint/test/lazy-estree.test.ts b/packages/compat-eslint/test/lazy-estree.test.ts index f6b446e..941a801 100644 --- a/packages/compat-eslint/test/lazy-estree.test.ts +++ b/packages/compat-eslint/test/lazy-estree.test.ts @@ -1653,95 +1653,17 @@ function findTsJsxExpr(sf: ts.SourceFile, attrName?: string): ts.JsxExpression | // such type appearing in our reachable output is automatically wrong. // // Walk a comprehensive fixture via visitor-keys (forces all getters), -// also bottom-up materialise every TS node, then assert no type starts -// with 'TS' AND isn't in the typescript-estree spec list. Catches new -// missing-skip cases as soon as they appear. +// also bottom-up materialise every TS node, then assert no type appears +// that isn't in upstream typescript-estree's `AST_NODE_TYPES` enum. Pulls +// the truth list directly from the upstream package — when typescript- +// estree adds a new type, we get it for free; we don't have to remember +// to update a hand-coded list. { const visitorKeys = require('../lib/visitor-keys.js') as { visitorKeys: Record }; - - // typescript-estree's published TS-* node types. Anything starting - // with 'TS' that ISN'T here is a phantom GenericTSNode. - const TYPESCRIPT_ESTREE_TS_TYPES = new Set([ - 'TSAbstractAccessorProperty', - 'TSAbstractKeyword', - 'TSAbstractMethodDefinition', - 'TSAbstractPropertyDefinition', - 'TSAnyKeyword', - 'TSArrayType', - 'TSAsExpression', - 'TSAsyncKeyword', - 'TSBigIntKeyword', - 'TSBooleanKeyword', - 'TSCallSignatureDeclaration', - 'TSClassImplements', - 'TSConditionalType', - 'TSConstructSignatureDeclaration', - 'TSConstructorType', - 'TSDeclareFunction', - 'TSDeclareKeyword', - 'TSEmptyBodyFunctionExpression', - 'TSEnumBody', - 'TSEnumDeclaration', - 'TSEnumMember', - 'TSExportAssignment', - 'TSExportKeyword', - 'TSExternalModuleReference', - 'TSFunctionType', - 'TSImportEqualsDeclaration', - 'TSImportType', - 'TSIndexSignature', - 'TSIndexedAccessType', - 'TSInferType', - 'TSInstantiationExpression', - 'TSInterfaceBody', - 'TSInterfaceDeclaration', - 'TSInterfaceHeritage', - 'TSIntersectionType', - 'TSIntrinsicKeyword', - 'TSLiteralType', - 'TSMappedType', - 'TSMethodSignature', - 'TSModuleBlock', - 'TSModuleDeclaration', - 'TSNamedTupleMember', - 'TSNamespaceExportDeclaration', - 'TSNeverKeyword', - 'TSNonNullExpression', - 'TSNullKeyword', - 'TSNumberKeyword', - 'TSObjectKeyword', - 'TSOptionalType', - 'TSParameterProperty', - 'TSPrivateKeyword', - 'TSPropertySignature', - 'TSProtectedKeyword', - 'TSPublicKeyword', - 'TSQualifiedName', - 'TSReadonlyKeyword', - 'TSRestType', - 'TSSatisfiesExpression', - 'TSStaticKeyword', - 'TSStringKeyword', - 'TSSymbolKeyword', - 'TSTemplateLiteralType', - 'TSThisType', - 'TSTupleType', - 'TSTypeAliasDeclaration', - 'TSTypeAnnotation', - 'TSTypeAssertion', - 'TSTypeLiteral', - 'TSTypeOperator', - 'TSTypeParameter', - 'TSTypeParameterDeclaration', - 'TSTypeParameterInstantiation', - 'TSTypePredicate', - 'TSTypeQuery', - 'TSTypeReference', - 'TSUndefinedKeyword', - 'TSUnionType', - 'TSUnknownKeyword', - 'TSVoidKeyword', - ]); + const { AST_NODE_TYPES } = require('@typescript-eslint/typescript-estree') as { + AST_NODE_TYPES: Record; + }; + const TYPESCRIPT_ESTREE_TS_TYPES = new Set(Object.values(AST_NODE_TYPES)); const fixtures: Array<{ name: string; code: string; tsx?: boolean }> = [ { From 8301a982da8688edd337121502093aca5626e50b Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sun, 3 May 2026 02:24:47 +0800 Subject: [PATCH 3/3] Update lazy-estree.ts --- packages/compat-eslint/lib/lazy-estree.ts | 229 ++++++++++++++++------ 1 file changed, 169 insertions(+), 60 deletions(-) diff --git a/packages/compat-eslint/lib/lazy-estree.ts b/packages/compat-eslint/lib/lazy-estree.ts index 5e5e5ba..0cc53e2 100644 --- a/packages/compat-eslint/lib/lazy-estree.ts +++ b/packages/compat-eslint/lib/lazy-estree.ts @@ -126,67 +126,168 @@ const EMPTY_ARRAY: never[] = Object.freeze([]) as never[]; // are dynamic via TypeKeywordNode, so they go in here too. type KnownEstreeType = // Core ESTree - | 'AccessorProperty' | 'ArrayExpression' | 'ArrayPattern' + | 'AccessorProperty' + | 'ArrayExpression' + | 'ArrayPattern' | 'ArrowFunctionExpression' - | 'AssignmentExpression' | 'AssignmentPattern' | 'AwaitExpression' - | 'BinaryExpression' | 'BlockStatement' | 'BreakStatement' - | 'CallExpression' | 'CatchClause' | 'ChainExpression' - | 'ClassBody' | 'ClassDeclaration' | 'ClassExpression' - | 'ConditionalExpression' | 'ContinueStatement' | 'DebuggerStatement' - | 'Decorator' | 'DoWhileStatement' | 'EmptyStatement' - | 'ExportAllDeclaration' | 'ExportDefaultDeclaration' - | 'ExportNamedDeclaration' | 'ExportSpecifier' | 'ExpressionStatement' - | 'ForInStatement' | 'ForOfStatement' | 'ForStatement' - | 'FunctionDeclaration' | 'FunctionExpression' | 'Identifier' - | 'IfStatement' | 'ImportAttribute' | 'ImportDeclaration' - | 'ImportDefaultSpecifier' | 'ImportExpression' | 'ImportNamespaceSpecifier' - | 'ImportSpecifier' | 'LabeledStatement' | 'Literal' - | 'LogicalExpression' | 'MemberExpression' | 'MetaProperty' - | 'MethodDefinition' | 'NewExpression' | 'ObjectExpression' - | 'ObjectPattern' | 'PrivateIdentifier' | 'Program' | 'Property' - | 'PropertyDefinition' | 'RestElement' | 'ReturnStatement' - | 'SequenceExpression' | 'SpreadElement' | 'StaticBlock' - | 'Super' | 'SwitchCase' | 'SwitchStatement' - | 'TaggedTemplateExpression' | 'TemplateElement' | 'TemplateLiteral' - | 'ThisExpression' | 'ThrowStatement' | 'TryStatement' - | 'UnaryExpression' | 'UpdateExpression' | 'VariableDeclaration' - | 'VariableDeclarator' | 'WhileStatement' | 'WithStatement' + | 'AssignmentExpression' + | 'AssignmentPattern' + | 'AwaitExpression' + | 'BinaryExpression' + | 'BlockStatement' + | 'BreakStatement' + | 'CallExpression' + | 'CatchClause' + | 'ChainExpression' + | 'ClassBody' + | 'ClassDeclaration' + | 'ClassExpression' + | 'ConditionalExpression' + | 'ContinueStatement' + | 'DebuggerStatement' + | 'Decorator' + | 'DoWhileStatement' + | 'EmptyStatement' + | 'ExportAllDeclaration' + | 'ExportDefaultDeclaration' + | 'ExportNamedDeclaration' + | 'ExportSpecifier' + | 'ExpressionStatement' + | 'ForInStatement' + | 'ForOfStatement' + | 'ForStatement' + | 'FunctionDeclaration' + | 'FunctionExpression' + | 'Identifier' + | 'IfStatement' + | 'ImportAttribute' + | 'ImportDeclaration' + | 'ImportDefaultSpecifier' + | 'ImportExpression' + | 'ImportNamespaceSpecifier' + | 'ImportSpecifier' + | 'LabeledStatement' + | 'Literal' + | 'LogicalExpression' + | 'MemberExpression' + | 'MetaProperty' + | 'MethodDefinition' + | 'NewExpression' + | 'ObjectExpression' + | 'ObjectPattern' + | 'PrivateIdentifier' + | 'Program' + | 'Property' + | 'PropertyDefinition' + | 'RestElement' + | 'ReturnStatement' + | 'SequenceExpression' + | 'SpreadElement' + | 'StaticBlock' + | 'Super' + | 'SwitchCase' + | 'SwitchStatement' + | 'TaggedTemplateExpression' + | 'TemplateElement' + | 'TemplateLiteral' + | 'ThisExpression' + | 'ThrowStatement' + | 'TryStatement' + | 'UnaryExpression' + | 'UpdateExpression' + | 'VariableDeclaration' + | 'VariableDeclarator' + | 'WhileStatement' + | 'WithStatement' | 'YieldExpression' // JSX - | 'JSXAttribute' | 'JSXClosingElement' | 'JSXClosingFragment' - | 'JSXElement' | 'JSXEmptyExpression' | 'JSXExpressionContainer' - | 'JSXFragment' | 'JSXIdentifier' | 'JSXMemberExpression' - | 'JSXNamespacedName' | 'JSXOpeningElement' | 'JSXOpeningFragment' - | 'JSXSpreadAttribute' | 'JSXSpreadChild' | 'JSXText' + | 'JSXAttribute' + | 'JSXClosingElement' + | 'JSXClosingFragment' + | 'JSXElement' + | 'JSXEmptyExpression' + | 'JSXExpressionContainer' + | 'JSXFragment' + | 'JSXIdentifier' + | 'JSXMemberExpression' + | 'JSXNamespacedName' + | 'JSXOpeningElement' + | 'JSXOpeningFragment' + | 'JSXSpreadAttribute' + | 'JSXSpreadChild' + | 'JSXText' // TS-specific (composite types) - | 'TSAbstractAccessorProperty' | 'TSAbstractKeyword' - | 'TSAbstractMethodDefinition' | 'TSAbstractPropertyDefinition' - | 'TSArrayType' | 'TSAsExpression' | 'TSCallSignatureDeclaration' - | 'TSClassImplements' | 'TSConditionalType' - | 'TSConstructSignatureDeclaration' | 'TSConstructorType' - | 'TSDeclareFunction' | 'TSEmptyBodyFunctionExpression' - | 'TSEnumBody' | 'TSEnumDeclaration' | 'TSEnumMember' - | 'TSExportAssignment' | 'TSExternalModuleReference' - | 'TSFunctionType' | 'TSImportEqualsDeclaration' | 'TSImportType' - | 'TSIndexSignature' | 'TSIndexedAccessType' | 'TSInferType' - | 'TSInstantiationExpression' | 'TSInterfaceBody' - | 'TSInterfaceDeclaration' | 'TSInterfaceHeritage' - | 'TSIntersectionType' | 'TSLiteralType' | 'TSMappedType' - | 'TSMethodSignature' | 'TSModuleBlock' | 'TSModuleDeclaration' - | 'TSNamedTupleMember' | 'TSNamespaceExportDeclaration' - | 'TSNonNullExpression' | 'TSOptionalType' | 'TSParameterProperty' - | 'TSPropertySignature' | 'TSQualifiedName' | 'TSRestType' - | 'TSSatisfiesExpression' | 'TSTemplateLiteralType' | 'TSThisType' - | 'TSTupleType' | 'TSTypeAliasDeclaration' | 'TSTypeAnnotation' - | 'TSTypeAssertion' | 'TSTypeLiteral' | 'TSTypeOperator' - | 'TSTypeParameter' | 'TSTypeParameterDeclaration' - | 'TSTypeParameterInstantiation' | 'TSTypePredicate' | 'TSTypeQuery' - | 'TSTypeReference' | 'TSUnionType' + | 'TSAbstractAccessorProperty' + | 'TSAbstractKeyword' + | 'TSAbstractMethodDefinition' + | 'TSAbstractPropertyDefinition' + | 'TSArrayType' + | 'TSAsExpression' + | 'TSCallSignatureDeclaration' + | 'TSClassImplements' + | 'TSConditionalType' + | 'TSConstructSignatureDeclaration' + | 'TSConstructorType' + | 'TSDeclareFunction' + | 'TSEmptyBodyFunctionExpression' + | 'TSEnumBody' + | 'TSEnumDeclaration' + | 'TSEnumMember' + | 'TSExportAssignment' + | 'TSExternalModuleReference' + | 'TSFunctionType' + | 'TSImportEqualsDeclaration' + | 'TSImportType' + | 'TSIndexSignature' + | 'TSIndexedAccessType' + | 'TSInferType' + | 'TSInstantiationExpression' + | 'TSInterfaceBody' + | 'TSInterfaceDeclaration' + | 'TSInterfaceHeritage' + | 'TSIntersectionType' + | 'TSLiteralType' + | 'TSMappedType' + | 'TSMethodSignature' + | 'TSModuleBlock' + | 'TSModuleDeclaration' + | 'TSNamedTupleMember' + | 'TSNamespaceExportDeclaration' + | 'TSNonNullExpression' + | 'TSOptionalType' + | 'TSParameterProperty' + | 'TSPropertySignature' + | 'TSQualifiedName' + | 'TSRestType' + | 'TSSatisfiesExpression' + | 'TSTemplateLiteralType' + | 'TSThisType' + | 'TSTupleType' + | 'TSTypeAliasDeclaration' + | 'TSTypeAnnotation' + | 'TSTypeAssertion' + | 'TSTypeLiteral' + | 'TSTypeOperator' + | 'TSTypeParameter' + | 'TSTypeParameterDeclaration' + | 'TSTypeParameterInstantiation' + | 'TSTypePredicate' + | 'TSTypeQuery' + | 'TSTypeReference' + | 'TSUnionType' // TS keyword types (TypeKeywordNode dynamic dispatch) - | 'TSAnyKeyword' | 'TSBigIntKeyword' | 'TSBooleanKeyword' - | 'TSIntrinsicKeyword' | 'TSNeverKeyword' | 'TSNullKeyword' - | 'TSNumberKeyword' | 'TSObjectKeyword' | 'TSStringKeyword' - | 'TSSymbolKeyword' | 'TSUndefinedKeyword' | 'TSUnknownKeyword' + | 'TSAnyKeyword' + | 'TSBigIntKeyword' + | 'TSBooleanKeyword' + | 'TSIntrinsicKeyword' + | 'TSNeverKeyword' + | 'TSNullKeyword' + | 'TSNumberKeyword' + | 'TSObjectKeyword' + | 'TSStringKeyword' + | 'TSSymbolKeyword' + | 'TSUndefinedKeyword' + | 'TSUnknownKeyword' | 'TSVoidKeyword'; function getLocFor(ast: ts.SourceFile, start: number, end: number) { @@ -2361,10 +2462,18 @@ class TSTypeAnnotationNode extends LazyNode { // subset so the constructor's `type` parameter can't accept a // non-keyword name by mistake. type TypeKeyword = - | 'TSAnyKeyword' | 'TSBigIntKeyword' | 'TSBooleanKeyword' - | 'TSIntrinsicKeyword' | 'TSNeverKeyword' | 'TSNullKeyword' - | 'TSNumberKeyword' | 'TSObjectKeyword' | 'TSStringKeyword' - | 'TSSymbolKeyword' | 'TSUndefinedKeyword' | 'TSUnknownKeyword' + | 'TSAnyKeyword' + | 'TSBigIntKeyword' + | 'TSBooleanKeyword' + | 'TSIntrinsicKeyword' + | 'TSNeverKeyword' + | 'TSNullKeyword' + | 'TSNumberKeyword' + | 'TSObjectKeyword' + | 'TSStringKeyword' + | 'TSSymbolKeyword' + | 'TSUndefinedKeyword' + | 'TSUnknownKeyword' | 'TSVoidKeyword'; class TypeKeywordNode extends LazyNode { readonly type: TypeKeyword;