Skip to content

Support extends syntax for Flow type parameter bounds#17857

Closed
marcoww6 wants to merge 2 commits into
babel:mainfrom
marcoww6:flow-extends-type-param-bounds
Closed

Support extends syntax for Flow type parameter bounds#17857
marcoww6 wants to merge 2 commits into
babel:mainfrom
marcoww6:flow-extends-type-param-bounds

Conversation

@marcoww6

@marcoww6 marcoww6 commented Mar 6, 2026

Copy link
Copy Markdown

Summary

  • Flow is migrating type parameter bounds from colon syntax (T: S) to extends syntax (T extends S)
  • Update flowParseTypeParameter to accept both : and extends as bound delimiters, producing the same TypeAnnotation bound node in either case
  • Replace the flowParseTypeAnnotatableIdentifier call with flowParseRestrictedIdentifier directly, then handle the bound inline with an OR check for both token types

Test plan

  • Added test fixtures for extends syntax: class, function, type alias with default, and multiple type params
  • Verified AST output matches the existing colon syntax output
  • All 18 Flow test suites pass (16,193 tests)

@babel-bot

babel-bot commented Mar 6, 2026

Copy link
Copy Markdown
Collaborator

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/61127

@pkg-pr-new

pkg-pr-new Bot commented Mar 6, 2026

Copy link
Copy Markdown

Open in StackBlitz

commit: 6dccbc8

Flow is migrating type parameter bounds from colon syntax (`T: S`) to
`extends` syntax (`T extends S`). Update the parser to accept both
delimiters, producing the same TypeAnnotation bound node in either case.
@marcoww6 marcoww6 force-pushed the flow-extends-type-param-bounds branch from 211ffa3 to 5b9249d Compare March 6, 2026 01:09

@JLHwung JLHwung 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.

Thank you for your contribution.

@@ -0,0 +1 @@
class A<T extends Foo> {}

@JLHwung JLHwung Mar 10, 2026

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.

Is it semantically equivalent to

class A<T: Foo> {}

?

The babel-generator currently always generates : type for extends type because the AST is the same. Since extends type might break old flow versions, we may have to add a new babel-generator option to always emit extends type now that flow is migrating to the extends syntax.

// @ts-expect-error migrate to Babel types
node.bound = ident.typeAnnotation;

if (this.match(tt.colon) || this.match(tt._extends)) {

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.

Suggested change
if (this.match(tt.colon) || this.match(tt._extends)) {
if (this.match(tt.colon) || this.isContextual(tt._extends)) {

The parser should reject invalid production such as

class A<T \u65xtends Foo> {}

this.next();
boundNode.typeAnnotation = this.flowParseType();
// @ts-expect-error migrate to Babel types
node.bound = this.finishNode(boundNode, "TypeAnnotation");

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.

Suggested change
node.bound = this.finishNode(boundNode, "TypeAnnotation");
node.bound = this.finishNode(boundNode, "TypeAnnotation");
this.resetEndLocation(ident);

The end location should be adjusted such that the range of the identifier node covers its .bound child node.

Could you add a test case for comment attachment? For example,

function F</* 0 */T/* 1 */extends/* 2 */Foo/* 3 */>() {}

where 0 should be the leading comment of the identifier node, 3 should be the trailing comment.


const variance = this.flowParseVariance();

const ident = this.flowParseTypeAnnotatableIdentifier();

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.

With this change, the flowParseTypeAnnotatableIdentifier will be always called with allowPrimitiveOverride: true, could you also simplify its signature?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants