Skip to content

Commit 31c3ef5

Browse files
authored
Merge pull request #22251 from jack-williams/jack-williams/no-implicit-symbol-to-string
Fix #19666: Check for symbol types in template expressions
2 parents 849ecdf + 5338500 commit 31c3ef5

10 files changed

+201
-1
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19684,7 +19684,9 @@ namespace ts {
1968419684
// A place where we actually *are* concerned with the expressions' types are
1968519685
// in tagged templates.
1968619686
forEach(node.templateSpans, templateSpan => {
19687-
checkExpression(templateSpan.expression);
19687+
if (maybeTypeOfKind(checkExpression(templateSpan.expression), TypeFlags.ESSymbolLike)) {
19688+
error(templateSpan.expression, Diagnostics.Type_0_cannot_be_converted_to_type_1, typeToString(esSymbolType), typeToString(stringType));
19689+
}
1968819690
});
1968919691

1969019692
return stringType;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
tests/cases/compiler/noImplicitSymbolToString.ts(6,30): error TS2352: Type 'symbol' cannot be converted to type 'string'.
2+
tests/cases/compiler/noImplicitSymbolToString.ts(7,30): error TS2469: The '+' operator cannot be applied to type 'symbol'.
3+
tests/cases/compiler/noImplicitSymbolToString.ts(8,8): error TS2469: The '+=' operator cannot be applied to type 'symbol'.
4+
tests/cases/compiler/noImplicitSymbolToString.ts(13,47): error TS2352: Type 'symbol' cannot be converted to type 'string'.
5+
tests/cases/compiler/noImplicitSymbolToString.ts(13,90): error TS2352: Type 'symbol' cannot be converted to type 'string'.
6+
7+
8+
==== tests/cases/compiler/noImplicitSymbolToString.ts (5 errors) ====
9+
// Fix #19666
10+
11+
let symbol!: symbol;
12+
let str = "hello ";
13+
14+
const templateStr = `hello ${symbol}`;
15+
~~~~~~
16+
!!! error TS2352: Type 'symbol' cannot be converted to type 'string'.
17+
const appendStr = "hello " + symbol;
18+
~~~~~~
19+
!!! error TS2469: The '+' operator cannot be applied to type 'symbol'.
20+
str += symbol;
21+
~~~~~~
22+
!!! error TS2469: The '+=' operator cannot be applied to type 'symbol'.
23+
24+
let symbolUnionNumber!: symbol | number;
25+
let symbolUnionString!: symbol | string;
26+
27+
const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`;
28+
~~~~~~~~~~~~~~~~~
29+
!!! error TS2352: Type 'symbol' cannot be converted to type 'string'.
30+
~~~~~~~~~~~~~~~~~
31+
!!! error TS2352: Type 'symbol' cannot be converted to type 'string'.
32+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [noImplicitSymbolToString.ts]
2+
// Fix #19666
3+
4+
let symbol!: symbol;
5+
let str = "hello ";
6+
7+
const templateStr = `hello ${symbol}`;
8+
const appendStr = "hello " + symbol;
9+
str += symbol;
10+
11+
let symbolUnionNumber!: symbol | number;
12+
let symbolUnionString!: symbol | string;
13+
14+
const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`;
15+
16+
17+
//// [noImplicitSymbolToString.js]
18+
// Fix #19666
19+
var symbol;
20+
var str = "hello ";
21+
var templateStr = "hello " + symbol;
22+
var appendStr = "hello " + symbol;
23+
str += symbol;
24+
var symbolUnionNumber;
25+
var symbolUnionString;
26+
var templateStrUnion = "union with number " + symbolUnionNumber + " and union with string " + symbolUnionString;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/compiler/noImplicitSymbolToString.ts ===
2+
// Fix #19666
3+
4+
let symbol!: symbol;
5+
>symbol : Symbol(symbol, Decl(noImplicitSymbolToString.ts, 2, 3))
6+
7+
let str = "hello ";
8+
>str : Symbol(str, Decl(noImplicitSymbolToString.ts, 3, 3))
9+
10+
const templateStr = `hello ${symbol}`;
11+
>templateStr : Symbol(templateStr, Decl(noImplicitSymbolToString.ts, 5, 5))
12+
>symbol : Symbol(symbol, Decl(noImplicitSymbolToString.ts, 2, 3))
13+
14+
const appendStr = "hello " + symbol;
15+
>appendStr : Symbol(appendStr, Decl(noImplicitSymbolToString.ts, 6, 5))
16+
>symbol : Symbol(symbol, Decl(noImplicitSymbolToString.ts, 2, 3))
17+
18+
str += symbol;
19+
>str : Symbol(str, Decl(noImplicitSymbolToString.ts, 3, 3))
20+
>symbol : Symbol(symbol, Decl(noImplicitSymbolToString.ts, 2, 3))
21+
22+
let symbolUnionNumber!: symbol | number;
23+
>symbolUnionNumber : Symbol(symbolUnionNumber, Decl(noImplicitSymbolToString.ts, 9, 3))
24+
25+
let symbolUnionString!: symbol | string;
26+
>symbolUnionString : Symbol(symbolUnionString, Decl(noImplicitSymbolToString.ts, 10, 3))
27+
28+
const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`;
29+
>templateStrUnion : Symbol(templateStrUnion, Decl(noImplicitSymbolToString.ts, 12, 5))
30+
>symbolUnionNumber : Symbol(symbolUnionNumber, Decl(noImplicitSymbolToString.ts, 9, 3))
31+
>symbolUnionString : Symbol(symbolUnionString, Decl(noImplicitSymbolToString.ts, 10, 3))
32+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
=== tests/cases/compiler/noImplicitSymbolToString.ts ===
2+
// Fix #19666
3+
4+
let symbol!: symbol;
5+
>symbol : symbol
6+
7+
let str = "hello ";
8+
>str : string
9+
>"hello " : "hello "
10+
11+
const templateStr = `hello ${symbol}`;
12+
>templateStr : string
13+
>`hello ${symbol}` : string
14+
>symbol : symbol
15+
16+
const appendStr = "hello " + symbol;
17+
>appendStr : string
18+
>"hello " + symbol : string
19+
>"hello " : "hello "
20+
>symbol : symbol
21+
22+
str += symbol;
23+
>str += symbol : string
24+
>str : string
25+
>symbol : symbol
26+
27+
let symbolUnionNumber!: symbol | number;
28+
>symbolUnionNumber : number | symbol
29+
30+
let symbolUnionString!: symbol | string;
31+
>symbolUnionString : string | symbol
32+
33+
const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`;
34+
>templateStrUnion : string
35+
>`union with number ${symbolUnionNumber} and union with string ${symbolUnionString}` : string
36+
>symbolUnionNumber : number | symbol
37+
>symbolUnionString : string | symbol
38+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [taggedTemplateStringWithSymbolExpression01.ts]
2+
// taggedTemplateStringWithSymbolExpression01.ts
3+
4+
declare function foo(template: any, val: symbol): number;
5+
let x!: symbol;
6+
7+
let result: number = foo`${x}`;
8+
9+
10+
//// [taggedTemplateStringWithSymbolExpression01.js]
11+
// taggedTemplateStringWithSymbolExpression01.ts
12+
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
13+
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
14+
return cooked;
15+
};
16+
var x;
17+
var result = foo(__makeTemplateObject(["", ""], ["", ""]), x);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/compiler/taggedTemplateStringWithSymbolExpression01.ts ===
2+
// taggedTemplateStringWithSymbolExpression01.ts
3+
4+
declare function foo(template: any, val: symbol): number;
5+
>foo : Symbol(foo, Decl(taggedTemplateStringWithSymbolExpression01.ts, 0, 0))
6+
>template : Symbol(template, Decl(taggedTemplateStringWithSymbolExpression01.ts, 2, 21))
7+
>val : Symbol(val, Decl(taggedTemplateStringWithSymbolExpression01.ts, 2, 35))
8+
9+
let x!: symbol;
10+
>x : Symbol(x, Decl(taggedTemplateStringWithSymbolExpression01.ts, 3, 3))
11+
12+
let result: number = foo`${x}`;
13+
>result : Symbol(result, Decl(taggedTemplateStringWithSymbolExpression01.ts, 5, 3))
14+
>foo : Symbol(foo, Decl(taggedTemplateStringWithSymbolExpression01.ts, 0, 0))
15+
>x : Symbol(x, Decl(taggedTemplateStringWithSymbolExpression01.ts, 3, 3))
16+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/compiler/taggedTemplateStringWithSymbolExpression01.ts ===
2+
// taggedTemplateStringWithSymbolExpression01.ts
3+
4+
declare function foo(template: any, val: symbol): number;
5+
>foo : (template: any, val: symbol) => number
6+
>template : any
7+
>val : symbol
8+
9+
let x!: symbol;
10+
>x : symbol
11+
12+
let result: number = foo`${x}`;
13+
>result : number
14+
>foo`${x}` : number
15+
>foo : (template: any, val: symbol) => number
16+
>`${x}` : string
17+
>x : symbol
18+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Fix #19666
2+
3+
let symbol!: symbol;
4+
let str = "hello ";
5+
6+
const templateStr = `hello ${symbol}`;
7+
const appendStr = "hello " + symbol;
8+
str += symbol;
9+
10+
let symbolUnionNumber!: symbol | number;
11+
let symbolUnionString!: symbol | string;
12+
13+
const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// taggedTemplateStringWithSymbolExpression01.ts
2+
3+
declare function foo(template: any, val: symbol): number;
4+
let x!: symbol;
5+
6+
let result: number = foo`${x}`;

0 commit comments

Comments
 (0)