Skip to content

Commit

Permalink
tsx: reject generic arrow functions without a ,
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jan 27, 2023
1 parent 1291b59 commit 8824778
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 1 deletion.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

## Unreleased

* Make parsing generic `async` arrow functions more strict in `.tsx` files

Previously esbuild's TypeScript parser incorrectly accepted the following code as valid:

```tsx
let fn = async <T> () => {};
```

The official TypeScript parser rejects this code because it thinks it's the identifier `async` followed by a JSX element starting with `<T>`. So with this release, esbuild will now reject this syntax in `.tsx` files too. You'll now have to add a comma after the type parameter to get generic arrow functions like this to parse in `.tsx` files:

```tsx
let fn = async <T,> () => {};
```

* Allow the `in` and `out` type parameter modifiers on class expressions

TypeScript 4.7 added the `in` and `out` modifiers on the type parameters of classes, interfaces, and type aliases. However, while TypeScript supported them on both class expressions and class statements, previously esbuild only supported them on class statements due to an oversight. This release now allows these modifiers on class expressions too:
Expand Down
2 changes: 1 addition & 1 deletion internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2716,7 +2716,7 @@ func (p *parser) parseAsyncPrefixExpr(asyncRange logger.Range, level js_ast.L, f
// "async<T>()"
// "async <T>() => {}"
case js_lexer.TLessThan:
if p.options.ts.Parse && p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking() {
if p.options.ts.Parse && (!p.options.jsx.Parse || p.isTSArrowFnJSX()) && p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking() {
p.lexer.Next()
return p.parseParenExpr(asyncRange.Loc, level, parenExprOpts{asyncRange: asyncRange})
}
Expand Down
7 changes: 7 additions & 0 deletions internal/js_parser/ts_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2380,6 +2380,13 @@ func TestTSJSX(t *testing.T) {
expectParseErrorTSX(t, "(<T = X>(y))", "<stdin>: ERROR: Expected \"=>\" but found \")\"\n")
expectParseErrorTSX(t, "(<T, X>(y))", "<stdin>: ERROR: Expected \"=>\" but found \")\"\n")
expectParseErrorTSX(t, "(<T, X>y => {})", "<stdin>: ERROR: Expected \"(\" but found \"y\"\n")

// TypeScript doesn't currently parse these even though it seems unambiguous
expectPrintedTSX(t, "async <T,>() => {}", "async () => {\n};\n")
expectPrintedTSX(t, "async <T extends X>() => {}", "async () => {\n};\n")
expectPrintedTSX(t, "async <T>()", "async();\n")
expectParseErrorTSX(t, "async <T>() => {}", "<stdin>: ERROR: Expected \";\" but found \"=>\"\n")
expectParseErrorTSX(t, "async <T extends>() => {}", "<stdin>: ERROR: Expected \";\" but found \"extends\"\n")
}

func TestTSNoAmbiguousLessThan(t *testing.T) {
Expand Down

0 comments on commit 8824778

Please sign in to comment.