Skip to content

Replace Node interface with discriminated unions - #64040

Open
Arnaud Barré (ArnaudBarre) wants to merge 5 commits into
microsoft:mainfrom
ArnaudBarre:ast-use-unions
Open

Replace Node interface with discriminated unions #64040
Arnaud Barré (ArnaudBarre) wants to merge 5 commits into
microsoft:mainfrom
ArnaudBarre:ast-use-unions

Conversation

@ArnaudBarre

Copy link
Copy Markdown

Copilot AI balanced review requested due to automatic review settings August 26, 2026 21:27
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Aug 26, 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.

Pull request overview

Reworks AST typings so Node and major node categories narrow through discriminated unions.

Changes:

  • Introduces NodeBase as the structural AST root.
  • Generates concrete unions for Node, expressions, statements, types, and declarations.
  • Includes aliased syntax kinds in discriminants.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
tools/scripts/tsc/generate-ts-ast.ts Generates discriminated AST unions.
packages/typescript/src/ast/ast.ts Introduces the common NodeBase interface.
packages/typescript/src/ast/ast.generated.ts Contains regenerated AST unions and kinds.

Comment thread packages/typescript/src/ast/ast.generated.ts
}

export interface Node extends ReadonlyTextRange {
export interface NodeBase extends ReadonlyTextRange {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is obviously a break on purpose, but I know that some consumers like TSESLint do patch in node types for compat reasons, which makes me wonder if the type should be defined as some goofy NodeRegistry interface + keyof typeof

But, I don't think that works for kinds anyway. Would have to cross check

Comment on lines +388 to +392
const allNodesNames = api
.nodes()
.map(node => node.name)
.sort((a, b) => a.localeCompare(b));
parts.push(`export type Node = ${allNodesNames.join(" | ")};`);

@ArnaudBarre Arnaud Barré (ArnaudBarre) Aug 26, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Is this kind of tests expected?
(AI generated from Eli (@lishaduck) exploration)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nah, this is copilot running out of ideas 😄


function isUnaryExpressionKind(kind: SyntaxKind): boolean {
switch (kind) {
export function isUnaryExpression(node: Node): node is PrefixUnaryExpression | PostfixUnaryExpression | DeleteExpression | TypeOfExpression | VoidExpression | AwaitExpression | TypeAssertion | LeftHandSideExpression {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The current ast.json doesn't trigger an enum for UnaryExpression, this could be changed

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would think that we'd want this as strong as possible; I think the downstream people like ts-morph and so on have a good handle on what we could be stronger about too?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Do you want me to do it in this PR?
There are quite some improvements the AI did in this exploration but it feels a bit orthogonal to the goal of the PR. Some of them should probably be considered outside of the "Node as discriminated union"

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

Labels

None yet

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

3 participants