diff --git a/internal/js_parser/js_parser.go b/internal/js_parser/js_parser.go index 8726b91209e..6e94b5c14fb 100644 --- a/internal/js_parser/js_parser.go +++ b/internal/js_parser/js_parser.go @@ -2977,6 +2977,9 @@ func (p *parser) parsePrefix(level js_ast.L, errors *deferredErrors, flags exprF })} } + // Allow `const a = b` + p.trySkipTypeScriptTypeArgumentsWithBacktracking() + ref := p.storeNameInRef(name) return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}} diff --git a/internal/js_parser/ts_parser.go b/internal/js_parser/ts_parser.go index a76edcd55d5..969338e983e 100644 --- a/internal/js_parser/ts_parser.go +++ b/internal/js_parser/ts_parser.go @@ -376,6 +376,7 @@ func (p *parser) skipTypeScriptTypeWithOpts(level js_ast.L, opts skipTypeOpts) { } p.lexer.Next() } + p.skipTypeScriptTypeArguments(false /* isInsideJSXElement */) } case js_lexer.TOpenBracket: @@ -797,10 +798,12 @@ func (p *parser) canFollowTypeArgumentsInExpression() bool { return true case - // These cases can't legally follow a type arg list. However, they're not - // legal expressions either. The user is probably in the middle of a - // generic type. So treat it as such. + // These tokens can't follow in a call expression, + // nor can they start an expression. + // So, consider the type argument list part of an instantiation expression. + js_lexer.TComma, // foo, js_lexer.TDot, // foo. + js_lexer.TQuestionDot, // foo?. js_lexer.TCloseParen, // foo) js_lexer.TCloseBracket, // foo] js_lexer.TColon, // foo: @@ -820,14 +823,6 @@ func (p *parser) canFollowTypeArgumentsInExpression() bool { js_lexer.TEndOfFile: // foo return true - case - // We don't want to treat these as type arguments. Otherwise we'll parse - // this as an invocation expression. Instead, we want to parse out the - // expression in isolation from the type arguments. - js_lexer.TComma, // foo, - js_lexer.TOpenBrace: // foo { - return false - default: // Anything else treat as an expression. return false diff --git a/internal/js_parser/ts_parser_test.go b/internal/js_parser/ts_parser_test.go index b29f6130d31..6cdd2bb1b4b 100644 --- a/internal/js_parser/ts_parser_test.go +++ b/internal/js_parser/ts_parser_test.go @@ -1564,6 +1564,8 @@ func TestTSNew(t *testing.T) { expectPrintedTS(t, "new Foo()", "new Foo();\n") expectPrintedTS(t, "new Foo()", "new Foo();\n") expectPrintedTS(t, "new Foo()", "new Foo();\n") + expectPrintedTS(t, "new Foo", "new Foo();\n") + expectPrintedTS(t, "new Foo", "new Foo();\n") expectPrintedTS(t, "new Foo!()", "new Foo();\n") expectPrintedTS(t, "new Foo!()", "new Foo();\n") @@ -1577,6 +1579,49 @@ func TestTSNew(t *testing.T) { expectParseError(t, "new Foo!()", ": ERROR: Unexpected \"!\"\n") } +func TestTSInstantiationExpression(t *testing.T) { + expectPrintedTS(t, "f", "f;\n") + expectPrintedTS(t, "f", "f;\n") + expectPrintedTS(t, "f.g", "f.g;\n") + expectPrintedTS(t, "f.g", "f.g;\n") + expectPrintedTS(t, "f.g", "f.g;\n") + expectPrintedTS(t, "f['g']", "f[\"g\"];\n") + expectPrintedTS(t, "(f)", "f;\n") + + // function call + expectPrintedTS(t, "const x1 = f\n(true);", "const x1 = f(true);\n") + // relational expression + expectPrintedTS(t, "const x1 = f\ntrue;", "const x1 = f < true > true;\n") + // instantiation expression + expectPrintedTS(t, "const x1 = f;\n(true);", "const x1 = f;\ntrue;\n") + + expectPrintedTS(t, "f?.();", "f?.();\n") + expectPrintedTS(t, "f?.();", "f?.();\n") + + expectPrintedTS(t, "f['g'];", "f < number > [\"g\"];\n") + + expectPrintedTS(t, "type T21 = typeof Array; f();", "f();\n") + expectPrintedTS(t, "type T22 = typeof Array; f();", "f();\n") + + expectPrintedTS(t, "f, g;", "f, g;\n") + expectPrintedTS(t, "[f];", "[f];\n") + expectPrintedTS(t, "f ? g : h;", "f ? g : h;\n") + expectPrintedTS(t, "f ^ g;", "f ^ g;\n") + expectPrintedTS(t, "f & g;", "f & g;\n") + expectPrintedTS(t, "f | g;", "f | g;\n") + expectPrintedTS(t, "f && g;", "f && g;\n") + expectPrintedTS(t, "f || g;", "f || g;\n") + expectPrintedTS(t, "f ?? g;", "f ?? g;\n") + expectPrintedTS(t, "{ f }", "{\n f;\n}\n") + expectPrintedTS(t, "f == g;", "f == g;\n") + expectPrintedTS(t, "f === g;", "f === g;\n") + expectPrintedTS(t, "f != g;", "f != g;\n") + expectPrintedTS(t, "f !== g;", "f !== g;\n") + + expectParseErrorTS(t, "const a8 = f;", ": ERROR: Unexpected \";\"\n") + expectParseErrorTS(t, "const b1 = f?.;", ": ERROR: Expected \"(\" but found \";\"\n") +} + func TestTSExponentiation(t *testing.T) { // More info: https://github.com/microsoft/TypeScript/issues/41755 expectParseErrorTS(t, "await x! ** 2", ": ERROR: Unexpected \"**\"\n")