diff --git a/tsc/internal/transformers/estransforms/optionalchain.go b/tsc/internal/transformers/estransforms/optionalchain.go index 33b269280f594..605795d8b38bf 100644 --- a/tsc/internal/transformers/estransforms/optionalchain.go +++ b/tsc/internal/transformers/estransforms/optionalchain.go @@ -140,6 +140,10 @@ func flattenChain(chain *ast.Node) flattenResult { debug.Assert(!isNonNullChain(chain)) links = append([]*ast.Node{chain}, links...) } + if ast.IsTaggedTemplateExpression(chain) { + // A tagged template has no expression; its tag is the base of the chain. + return flattenResult{chain.AsTaggedTemplateExpression().Tag, links} + } return flattenResult{chain.Expression(), links} } @@ -204,6 +208,17 @@ func (ch *optionalChainTransformer) visitOptionalExpression(node *ast.Node, capt ast.NodeFlagsNone, ) } + case ast.KindTaggedTemplateExpression: + // A tagged template can only be the head of the chain (flattenChain + // stops walking at it); re-tag its template onto the checked base. + t := segment.AsTaggedTemplateExpression() + rightExpression = ch.Factory().NewTaggedTemplateExpression( + rightExpression, + nil, /*questionDotToken*/ + t.TypeArguments, + ch.Visitor().VisitNode(t.Template), + ast.NodeFlagsNone, + ) } ch.EmitContext().SetOriginal(rightExpression, segment) } diff --git a/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).errors.txt b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).errors.txt new file mode 100644 index 0000000000000..703ee75bc68d7 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).errors.txt @@ -0,0 +1,26 @@ +repro.ts(1,1): error TS2304: Cannot find name 'e'. +repro.ts(2,1): error TS1005: ')' expected. +siblings.ts(2,5): error TS1358: Tagged template expressions are not permitted in an optional chain. +siblings.ts(3,5): error TS1358: Tagged template expressions are not permitted in an optional chain. +siblings.ts(4,4): error TS1358: Tagged template expressions are not permitted in an optional chain. + + +==== repro.ts (2 errors) ==== + e?.``( + ~ +!!! error TS2304: Cannot find name 'e'. + + +!!! error TS1005: ')' expected. +==== siblings.ts (3 errors) ==== + declare var a: any; + a?.b`c`; + ~~~ +!!! error TS1358: Tagged template expressions are not permitted in an optional chain. + a?.b`c`(); + ~~~ +!!! error TS1358: Tagged template expressions are not permitted in an optional chain. + a?.``.x; + ~~ +!!! error TS1358: Tagged template expressions are not permitted in an optional chain. + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).js b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).js new file mode 100644 index 0000000000000..a66557579d6f5 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).js @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/optionalChainTaggedTemplate.ts] //// + +//// [repro.ts] +e?.``( + +//// [siblings.ts] +declare var a: any; +a?.b`c`; +a?.b`c`(); +a?.``.x; + + +//// [repro.js] +"use strict"; +e === null || e === void 0 ? void 0 : e ``(); +//// [siblings.js] +"use strict"; +var _a; +(a === null || a === void 0 ? void 0 : a.b) `c`; +(_a = a === null || a === void 0 ? void 0 : a.b) === null || _a === void 0 ? void 0 : _a `c`(); +a === null || a === void 0 ? void 0 : a ``.x; diff --git a/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).symbols b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).symbols new file mode 100644 index 0000000000000..f1def366b522e --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).symbols @@ -0,0 +1,19 @@ +//// [tests/cases/compiler/optionalChainTaggedTemplate.ts] //// + +=== repro.ts === + +e?.``( + +=== siblings.ts === +declare var a: any; +>a : Symbol(a, Decl(siblings.ts, 0, 11)) + +a?.b`c`; +>a : Symbol(a, Decl(siblings.ts, 0, 11)) + +a?.b`c`(); +>a : Symbol(a, Decl(siblings.ts, 0, 11)) + +a?.``.x; +>a : Symbol(a, Decl(siblings.ts, 0, 11)) + diff --git a/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).types b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).types new file mode 100644 index 0000000000000..ebe370e79967b --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2017).types @@ -0,0 +1,35 @@ +//// [tests/cases/compiler/optionalChainTaggedTemplate.ts] //// + +=== repro.ts === +e?.``( +>e?.``( : any +>e?.`` : any +>e : any +>`` : "" + +=== siblings.ts === +declare var a: any; +>a : any + +a?.b`c`; +>a?.b`c` : any +>a?.b : any +>a : any +>b : any +>`c` : "c" + +a?.b`c`(); +>a?.b`c`() : any +>a?.b`c` : any +>a?.b : any +>a : any +>b : any +>`c` : "c" + +a?.``.x; +>a?.``.x : any +>a?.`` : any +>a : any +>`` : "" +>x : any + diff --git a/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).errors.txt b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).errors.txt new file mode 100644 index 0000000000000..703ee75bc68d7 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).errors.txt @@ -0,0 +1,26 @@ +repro.ts(1,1): error TS2304: Cannot find name 'e'. +repro.ts(2,1): error TS1005: ')' expected. +siblings.ts(2,5): error TS1358: Tagged template expressions are not permitted in an optional chain. +siblings.ts(3,5): error TS1358: Tagged template expressions are not permitted in an optional chain. +siblings.ts(4,4): error TS1358: Tagged template expressions are not permitted in an optional chain. + + +==== repro.ts (2 errors) ==== + e?.``( + ~ +!!! error TS2304: Cannot find name 'e'. + + +!!! error TS1005: ')' expected. +==== siblings.ts (3 errors) ==== + declare var a: any; + a?.b`c`; + ~~~ +!!! error TS1358: Tagged template expressions are not permitted in an optional chain. + a?.b`c`(); + ~~~ +!!! error TS1358: Tagged template expressions are not permitted in an optional chain. + a?.``.x; + ~~ +!!! error TS1358: Tagged template expressions are not permitted in an optional chain. + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).js b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).js new file mode 100644 index 0000000000000..d84b438b9c953 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).js @@ -0,0 +1,20 @@ +//// [tests/cases/compiler/optionalChainTaggedTemplate.ts] //// + +//// [repro.ts] +e?.``( + +//// [siblings.ts] +declare var a: any; +a?.b`c`; +a?.b`c`(); +a?.``.x; + + +//// [repro.js] +"use strict"; +e ``(); +//// [siblings.js] +"use strict"; +(a?.b) `c`; +(a?.b) `c`(); +a ``.x; diff --git a/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).symbols b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).symbols new file mode 100644 index 0000000000000..f1def366b522e --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).symbols @@ -0,0 +1,19 @@ +//// [tests/cases/compiler/optionalChainTaggedTemplate.ts] //// + +=== repro.ts === + +e?.``( + +=== siblings.ts === +declare var a: any; +>a : Symbol(a, Decl(siblings.ts, 0, 11)) + +a?.b`c`; +>a : Symbol(a, Decl(siblings.ts, 0, 11)) + +a?.b`c`(); +>a : Symbol(a, Decl(siblings.ts, 0, 11)) + +a?.``.x; +>a : Symbol(a, Decl(siblings.ts, 0, 11)) + diff --git a/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).types b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).types new file mode 100644 index 0000000000000..ebe370e79967b --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplate(target=es2024).types @@ -0,0 +1,35 @@ +//// [tests/cases/compiler/optionalChainTaggedTemplate.ts] //// + +=== repro.ts === +e?.``( +>e?.``( : any +>e?.`` : any +>e : any +>`` : "" + +=== siblings.ts === +declare var a: any; +>a : any + +a?.b`c`; +>a?.b`c` : any +>a?.b : any +>a : any +>b : any +>`c` : "c" + +a?.b`c`(); +>a?.b`c`() : any +>a?.b`c` : any +>a?.b : any +>a : any +>b : any +>`c` : "c" + +a?.``.x; +>a?.``.x : any +>a?.`` : any +>a : any +>`` : "" +>x : any + diff --git a/tsc/testdata/tests/cases/compiler/optionalChainTaggedTemplate.ts b/tsc/testdata/tests/cases/compiler/optionalChainTaggedTemplate.ts new file mode 100644 index 0000000000000..39609cdd1004c --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/optionalChainTaggedTemplate.ts @@ -0,0 +1,10 @@ +// @target: es2017, es2024 + +// @filename: repro.ts +e?.``( + +// @filename: siblings.ts +declare var a: any; +a?.b`c`; +a?.b`c`(); +a?.``.x;