Skip to content

Fix AST optionality - #65063

Open
Andrew Branch (andrewbranch) wants to merge 2 commits into
microsoft:mainfrom
andrewbranch:ast-optionality-fix
Open

Andrew Branch (andrewbranch) wants to merge 2 commits into
microsoft:mainfrom
andrewbranch:ast-optionality-fix

Conversation

@andrewbranch

Copy link
Copy Markdown
Member

Fixes #64864

Changed

  • ExportAssignment.type is now optional. Undefined for export default 0;.

  • PropertySignatureDeclaration.type is now optional. Undefined for p in interface I { p; }.

  • PropertySignatureDeclaration.initializer is now optional. Undefined for p in interface I { p: string; }.

  • IndexSignatureDeclaration.type is now optional. Undefined for interface I { [key: string] /*: missing type here */; }.

  • **ArrowFunction.equalsGreaterThanToken is now non-nil even for synthesized arrow functions, matching Strada's behavior.

  • TaggedTemplateExpression.questionDotToken is now optional. Undefined for tag`text`.

  • PropertyAssignment.type is now optional. Undefined for p in const obj = { p: 1 };.

  • ShorthandPropertyAssignment.type is now optional. Undefined for p in const obj = { p };.

  • JSDocTemplateTag.constraint is now optional. Undefined for /** @template T */ function f() {}.

  • JSDocSeeTag.nameExpression is now optional. Undefined for /** @see */ function f() {} (missing reference).

  • FunctionTypeNode.type is now required. In type F = () => number, it is the number type node; parser recovery also supplies a node when the return type is missing.

  • ConstructorTypeNode.type is now required. In type C = new () => object, it is the object type node; parser recovery likewise supplies a node when missing.

  • Separated CaseClause and DefaultClause in the schema and Go AST. CaseClause.expression remains required; DefaultClause has no expression property. CaseOrDefaultClause is a union, with shared statements/flow data in a base.

  • Factory-created boolean properties now default to false rather than undefined: Block.multiLine, ArrayLiteralExpression.multiLine, ObjectLiteralExpression.multiLine, ImportAttributes.multiLine, ExportDeclaration.isTypeOnly, SyntheticExpression.isSpread, JsxText.containsOnlyTriviaWhiteSpaces, and JSDocTypeLiteral.isArrayType.

  • Factory-created node arrays now initialize transformFlags to 0.

  • Factory-created nodes now compute modifierFlags from their modifiers, matching parsed nodes: None without modifiers, otherwise the combined syntactic modifier bitmask.

Not changed

node.parent is still typed as non-optional, which is a convenient lie inherited from Strada, and changing it would be pretty disruptive.

Copilot AI balanced review requested due to automatic review settings October 30, 2026 19:23
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Oct 30, 2026
@typescript-automation typescript-automation Bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Oct 30, 2026
@github-project-automation github-project-automation Bot moved this from Not started to Needs merge in PR Backlog Oct 30, 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 remain for the AST contract alignment and case/default clause separation.

No open issues 🎉

3 files not reviewed
  • tsc/internal/api/encoder/decoder_generated.go: Generated file
  • tsc/internal/api/encoder/encoder_generated.go: Generated file
  • tsc/internal/ast/ast_generated.go: Generated file
What changed in this PR

Addresses #64864 by aligning JavaScript API AST types with runtime values and updating the native compiler to use distinct case and default clause nodes.

Changes:

  • Corrects AST property optionality and removes expression from DefaultClause.
  • Ensures synthesized arrows have => tokens and initializes factory boolean values, modifier flags, and node-array transform flags.
  • Updates generators, serialization, compiler consumers, and regression tests to preserve these contracts.
File Description
tsc/​internal/​transformers/​moduletransforms/​commonjsmodule.go Updates case and default clauses separately during transformation.
tsc/​internal/​printer/​printer.go Prints distinct clause types through shared statement accessors.
tsc/​internal/​printer/​printer_test.go Exercises arrow printing with an omitted token.
tsc/​internal/​parser/​parser.go Constructs separate case and default nodes.
tsc/​internal/​ls/​utilities.go Updates clause tracking to use the union alias.
tsc/​internal/​ls/​folding.go Uses shared clause statement accessors for folding.
tsc/​internal/​ls/​completions.go Updates clause types and completion factories.
tsc/​internal/​checker/​checker.go Reads fallthrough data from the shared clause base.
tsc/​internal/​binder/​binder.go Adapts clause binding and fallthrough storage.
tsc/​internal/​ast/​nodeaccessors_test.go Tests arrow tokens, clause accessors, traversal, and cloning.
tsc/​internal/​ast/​ast.go Updates expression and statement accessors for split clauses.
tsc/​internal/​ast/​ast_generated.go Regenerates clause structures, factories, dispatch, and optionality comments.
tsc/​internal/​api/​encoder/​encoder_generated.go Encodes distinct child layouts for each clause type.
tsc/​internal/​api/​encoder/​decoder_generated.go Decodes clauses using their separate factories.
tools/​scripts/​tsc/​generate-ts-ast.ts Generates factory defaults and computed modifier flags.
tools/​scripts/​tsc/​generate-go-ast.ts Generates arrow-token defaults and shared clause accessors.
tools/​scripts/​tsc/​ast.json Defines corrected optionality and separate clause schemas.
packages/​typescript/​test/​sync/​ast.test.ts Adds runtime and type-level AST contract tests.
packages/​typescript/​src/​ast/​visitor.generated.ts Removes expression visitation from default clauses.
packages/​typescript/​src/​ast/​is.generated.ts Regenerates clause guards and adds a union guard.
packages/​typescript/​src/​ast/​factory.generated.ts Applies corrected factory signatures, defaults, and clause handling.
packages/​typescript/​src/​ast/​ast.ts Removes default clauses from HasExpression.
packages/​typescript/​src/​ast/​ast.generated.ts Exposes corrected property types and clause interfaces.
packages/​typescript/​src/​api/​node/​protocol.generated.ts Aligns default-clause protocol metadata with its statement-only layout.

Review effort: Balanced

@RyanCavanaugh

Copy link
Copy Markdown
Member

IndexSignatureDeclaration.type is now optional. Undefined for interface I { [key: string]

This is the only item in the entire list that's a syntax error, so seems out of place?

@andrewbranch
Andrew Branch (andrewbranch) added this pull request to the merge queue Oct 30, 2026
@andrewbranch
Andrew Branch (andrewbranch) removed this pull request from the merge queue due to a manual request Oct 30, 2026
@andrewbranch

Copy link
Copy Markdown
Member Author

Good catch; I misremembered that as legal along with interface I { p }. Strada typed it as non-optional but the parser doesn't produce a missing node there during recovery—actually, the syntax error you see is a grammar error, not a parse error.

This does seem to be the only case where an optional node child property is always defined in error-free code, so there's no other precedent to go on. Other grammar errors like this are context-dependent, e.g. VariableDeclaration.initializer is allowed to be missing in let x; but an error in const x;. I think the right option is either to keep it optional (as is in this PR), or to make it a proper parse error and synthesizing a missing identifier.

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

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Status: Needs merge

Development

Successfully merging this pull request may close these issues.

Some JS API types don't match their runtime values

4 participants