Skip to content

Commit cb88998

Browse files
authored
Evaluate simple template expressions (#53907)
1 parent dad9ae0 commit cb88998

File tree

104 files changed

+815
-535
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+815
-535
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29303,6 +29303,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2930329303
case SyntaxKind.NumericLiteral:
2930429304
case SyntaxKind.BigIntLiteral:
2930529305
case SyntaxKind.NoSubstitutionTemplateLiteral:
29306+
case SyntaxKind.TemplateExpression:
2930629307
case SyntaxKind.TrueKeyword:
2930729308
case SyntaxKind.FalseKeyword:
2930829309
case SyntaxKind.NullKeyword:
@@ -37355,7 +37356,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3735537356
texts.push(span.literal.text);
3735637357
types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType);
3735737358
}
37358-
return isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType) ? getTemplateLiteralType(texts, types) : stringType;
37359+
if (isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType)) {
37360+
return getTemplateLiteralType(texts, types);
37361+
}
37362+
const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluateTemplateExpression(node);
37363+
return evaluated ? getFreshTypeOfLiteralType(getStringLiteralType(evaluated)) : stringType;
3735937364
}
3736037365

3736137366
function isTemplateLiteralContextualType(type: Type): boolean {
@@ -43632,7 +43637,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4363243637
return value;
4363343638
}
4363443639

43635-
function evaluate(expr: Expression, location: Declaration): string | number | undefined {
43640+
function evaluate(expr: Expression, location?: Declaration): string | number | undefined {
4363643641
switch (expr.kind) {
4363743642
case SyntaxKind.PrefixUnaryExpression:
4363843643
const value = evaluate((expr as PrefixUnaryExpression).operand, location);
@@ -43689,11 +43694,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4368943694
const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true);
4369043695
if (symbol) {
4369143696
if (symbol.flags & SymbolFlags.EnumMember) {
43692-
return evaluateEnumMember(expr, symbol, location);
43697+
return location ? evaluateEnumMember(expr, symbol, location) : getEnumMemberValue(symbol.valueDeclaration as EnumMember);
4369343698
}
4369443699
if (isConstVariable(symbol)) {
4369543700
const declaration = symbol.valueDeclaration as VariableDeclaration | undefined;
43696-
if (declaration && !declaration.type && declaration.initializer && declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location)) {
43701+
if (declaration && !declaration.type && declaration.initializer && (!location || declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location))) {
4369743702
return evaluate(declaration.initializer, declaration);
4369843703
}
4369943704
}
@@ -43708,7 +43713,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4370843713
const name = escapeLeadingUnderscores(((expr as ElementAccessExpression).argumentExpression as StringLiteralLike).text);
4370943714
const member = rootSymbol.exports!.get(name);
4371043715
if (member) {
43711-
return evaluateEnumMember(expr, member, location);
43716+
return location ? evaluateEnumMember(expr, member, location) : getEnumMemberValue(member.valueDeclaration as EnumMember);
4371243717
}
4371343718
}
4371443719
}
@@ -43730,7 +43735,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4373043735
return getEnumMemberValue(declaration as EnumMember);
4373143736
}
4373243737

43733-
function evaluateTemplateExpression(expr: TemplateExpression, location: Declaration) {
43738+
function evaluateTemplateExpression(expr: TemplateExpression, location?: Declaration) {
4373443739
let result = expr.head.text;
4373543740
for (const span of expr.templateSpans) {
4373643741
const value = evaluate(span.expression, location);

tests/baselines/reference/asOperator3.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var c = `${123 + 456 as number} trailing`;
3030
var d = `Hello ${123} World` as string;
3131
>d : string
3232
>`Hello ${123} World` as string : string
33-
>`Hello ${123} World` : string
33+
>`Hello ${123} World` : "Hello 123 World"
3434
>123 : 123
3535

3636
var e = `Hello` as string;
@@ -43,7 +43,7 @@ var f = 1 + `${1} end of string` as string;
4343
>1 + `${1} end of string` as string : string
4444
>1 + `${1} end of string` : string
4545
>1 : 1
46-
>`${1} end of string` : string
46+
>`${1} end of string` : "1 end of string"
4747
>1 : 1
4848

4949
var g = tag `Hello ${123} World` as string;

tests/baselines/reference/classAttributeInferenceTemplate.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ class MyClass {
2121
>`foo` : "foo"
2222

2323
this.property2 = `foo-${variable}`; // Causes an error
24-
>this.property2 = `foo-${variable}` : string
24+
>this.property2 = `foo-${variable}` : "foo-something"
2525
>this.property2 : string
2626
>this : this
2727
>property2 : string
28-
>`foo-${variable}` : string
28+
>`foo-${variable}` : "foo-something"
2929
>variable : "something"
3030

3131
const localProperty = `foo-${variable}`; // Correctly inferred as `string`
32-
>localProperty : string
33-
>`foo-${variable}` : string
32+
>localProperty : "foo-something"
33+
>`foo-${variable}` : "foo-something"
3434
>variable : "something"
3535
}
3636
}

tests/baselines/reference/classAttributeInferenceTemplateJS.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ class MyClass {
2121
>`foo` : "foo"
2222

2323
this.property2 = `foo-${variable}`; // Causes an error
24-
>this.property2 = `foo-${variable}` : string
24+
>this.property2 = `foo-${variable}` : "foo-something"
2525
>this.property2 : string
2626
>this : this
2727
>property2 : string
28-
>`foo-${variable}` : string
28+
>`foo-${variable}` : "foo-something"
2929
>variable : "something"
3030

3131
const localProperty = `foo-${variable}`; // Correctly inferred as `string`
32-
>localProperty : string
33-
>`foo-${variable}` : string
32+
>localProperty : "foo-something"
33+
>`foo-${variable}` : "foo-something"
3434
>variable : "something"
3535
}
3636
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/compiler/discriminantUsingEvaluatableTemplateExpression.ts ===
2+
// repro from https://github.com/microsoft/TypeScript/issues/53888
3+
4+
type S = { d: "s"; cb: (x: string) => void };
5+
>S : Symbol(S, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 0, 0))
6+
>d : Symbol(d, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 2, 10))
7+
>cb : Symbol(cb, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 2, 18))
8+
>x : Symbol(x, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 2, 24))
9+
10+
type N = { d: "n"; cb: (x: number) => void };
11+
>N : Symbol(N, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 2, 45))
12+
>d : Symbol(d, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 3, 10))
13+
>cb : Symbol(cb, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 3, 18))
14+
>x : Symbol(x, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 3, 24))
15+
16+
declare function foo(foo: S | N): void;
17+
>foo : Symbol(foo, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 3, 45))
18+
>foo : Symbol(foo, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 5, 21))
19+
>S : Symbol(S, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 0, 0))
20+
>N : Symbol(N, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 2, 45))
21+
22+
foo({
23+
>foo : Symbol(foo, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 3, 45))
24+
25+
d: `${"s"}`,
26+
>d : Symbol(d, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 7, 5))
27+
28+
cb: (x) => {
29+
>cb : Symbol(cb, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 8, 14))
30+
>x : Symbol(x, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 9, 7))
31+
32+
x; // string
33+
>x : Symbol(x, Decl(discriminantUsingEvaluatableTemplateExpression.ts, 9, 7))
34+
35+
},
36+
});
37+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
=== tests/cases/compiler/discriminantUsingEvaluatableTemplateExpression.ts ===
2+
// repro from https://github.com/microsoft/TypeScript/issues/53888
3+
4+
type S = { d: "s"; cb: (x: string) => void };
5+
>S : { d: "s"; cb: (x: string) => void; }
6+
>d : "s"
7+
>cb : (x: string) => void
8+
>x : string
9+
10+
type N = { d: "n"; cb: (x: number) => void };
11+
>N : { d: "n"; cb: (x: number) => void; }
12+
>d : "n"
13+
>cb : (x: number) => void
14+
>x : number
15+
16+
declare function foo(foo: S | N): void;
17+
>foo : (foo: S | N) => void
18+
>foo : S | N
19+
20+
foo({
21+
>foo({ d: `${"s"}`, cb: (x) => { x; // string },}) : void
22+
>foo : (foo: S | N) => void
23+
>{ d: `${"s"}`, cb: (x) => { x; // string },} : { d: "s"; cb: (x: string) => void; }
24+
25+
d: `${"s"}`,
26+
>d : "s"
27+
>`${"s"}` : "s"
28+
>"s" : "s"
29+
30+
cb: (x) => {
31+
>cb : (x: string) => void
32+
>(x) => { x; // string } : (x: string) => void
33+
>x : string
34+
35+
x; // string
36+
>x : string
37+
38+
},
39+
});
40+

tests/baselines/reference/enumConstantMemberWithTemplateLiterals.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ enum T5 {
106106

107107
g = `1${"2"}3`,
108108
>g : T5.c
109-
>`1${"2"}3` : string
109+
>`1${"2"}3` : "123"
110110
>"2" : "2"
111111

112112
h = `1`.length

tests/baselines/reference/exponentiationOperatorWithTemplateStringInvalid.types

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,55 @@ var a = 1 ** `${ 3 }`;
33
>a : number
44
>1 ** `${ 3 }` : number
55
>1 : 1
6-
>`${ 3 }` : string
6+
>`${ 3 }` : "3"
77
>3 : 3
88

99
var b = 1 ** `2${ 3 }`;
1010
>b : number
1111
>1 ** `2${ 3 }` : number
1212
>1 : 1
13-
>`2${ 3 }` : string
13+
>`2${ 3 }` : "23"
1414
>3 : 3
1515

1616
var c = 1 ** `${ 3 }4`;
1717
>c : number
1818
>1 ** `${ 3 }4` : number
1919
>1 : 1
20-
>`${ 3 }4` : string
20+
>`${ 3 }4` : "34"
2121
>3 : 3
2222

2323
var d = 1 ** `2${ 3 }4`;
2424
>d : number
2525
>1 ** `2${ 3 }4` : number
2626
>1 : 1
27-
>`2${ 3 }4` : string
27+
>`2${ 3 }4` : "234"
2828
>3 : 3
2929

3030
var e = `${ 3 }` ** 5;
3131
>e : number
3232
>`${ 3 }` ** 5 : number
33-
>`${ 3 }` : string
33+
>`${ 3 }` : "3"
3434
>3 : 3
3535
>5 : 5
3636

3737
var f = `2${ 3 }` ** 5;
3838
>f : number
3939
>`2${ 3 }` ** 5 : number
40-
>`2${ 3 }` : string
40+
>`2${ 3 }` : "23"
4141
>3 : 3
4242
>5 : 5
4343

4444
var g = `${ 3 }4` ** 5;
4545
>g : number
4646
>`${ 3 }4` ** 5 : number
47-
>`${ 3 }4` : string
47+
>`${ 3 }4` : "34"
4848
>3 : 3
4949
>5 : 5
5050

5151
var h = `2${ 3 }4` ** 5;
5252
>h : number
5353
>`2${ 3 }4` ** 5 : number
54-
>`2${ 3 }4` : string
54+
>`2${ 3 }4` : "234"
5555
>3 : 3
5656
>5 : 5
5757

@@ -62,25 +62,25 @@ var k = 10;
6262
k **= `${ 3 }`;
6363
>k **= `${ 3 }` : number
6464
>k : number
65-
>`${ 3 }` : string
65+
>`${ 3 }` : "3"
6666
>3 : 3
6767

6868
k **= `2${ 3 }`;
6969
>k **= `2${ 3 }` : number
7070
>k : number
71-
>`2${ 3 }` : string
71+
>`2${ 3 }` : "23"
7272
>3 : 3
7373

7474
k **= `2${ 3 }4`;
7575
>k **= `2${ 3 }4` : number
7676
>k : number
77-
>`2${ 3 }4` : string
77+
>`2${ 3 }4` : "234"
7878
>3 : 3
7979

8080
k **= `2${ 3 }4`;
8181
>k **= `2${ 3 }4` : number
8282
>k : number
83-
>`2${ 3 }4` : string
83+
>`2${ 3 }4` : "234"
8484
>3 : 3
8585

8686

tests/baselines/reference/exponentiationOperatorWithTemplateStringInvalidES6.types

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,55 @@ var a = 1 ** `${ 3 }`;
33
>a : number
44
>1 ** `${ 3 }` : number
55
>1 : 1
6-
>`${ 3 }` : string
6+
>`${ 3 }` : "3"
77
>3 : 3
88

99
var b = 1 ** `2${ 3 }`;
1010
>b : number
1111
>1 ** `2${ 3 }` : number
1212
>1 : 1
13-
>`2${ 3 }` : string
13+
>`2${ 3 }` : "23"
1414
>3 : 3
1515

1616
var c = 1 ** `${ 3 }4`;
1717
>c : number
1818
>1 ** `${ 3 }4` : number
1919
>1 : 1
20-
>`${ 3 }4` : string
20+
>`${ 3 }4` : "34"
2121
>3 : 3
2222

2323
var d = 1 ** `2${ 3 }4`;
2424
>d : number
2525
>1 ** `2${ 3 }4` : number
2626
>1 : 1
27-
>`2${ 3 }4` : string
27+
>`2${ 3 }4` : "234"
2828
>3 : 3
2929

3030
var e = `${ 3 }` ** 5;
3131
>e : number
3232
>`${ 3 }` ** 5 : number
33-
>`${ 3 }` : string
33+
>`${ 3 }` : "3"
3434
>3 : 3
3535
>5 : 5
3636

3737
var f = `2${ 3 }` ** 5;
3838
>f : number
3939
>`2${ 3 }` ** 5 : number
40-
>`2${ 3 }` : string
40+
>`2${ 3 }` : "23"
4141
>3 : 3
4242
>5 : 5
4343

4444
var g = `${ 3 }4` ** 5;
4545
>g : number
4646
>`${ 3 }4` ** 5 : number
47-
>`${ 3 }4` : string
47+
>`${ 3 }4` : "34"
4848
>3 : 3
4949
>5 : 5
5050

5151
var h = `2${ 3 }4` ** 5;
5252
>h : number
5353
>`2${ 3 }4` ** 5 : number
54-
>`2${ 3 }4` : string
54+
>`2${ 3 }4` : "234"
5555
>3 : 3
5656
>5 : 5
5757

@@ -62,24 +62,24 @@ var k = 10;
6262
k **= `${ 3 }`;
6363
>k **= `${ 3 }` : number
6464
>k : number
65-
>`${ 3 }` : string
65+
>`${ 3 }` : "3"
6666
>3 : 3
6767

6868
k **= `2${ 3 }`;
6969
>k **= `2${ 3 }` : number
7070
>k : number
71-
>`2${ 3 }` : string
71+
>`2${ 3 }` : "23"
7272
>3 : 3
7373

7474
k **= `2${ 3 }4`;
7575
>k **= `2${ 3 }4` : number
7676
>k : number
77-
>`2${ 3 }4` : string
77+
>`2${ 3 }4` : "234"
7878
>3 : 3
7979

8080
kj **= `2${ 3 }4`;
8181
>kj **= `2${ 3 }4` : number
8282
>kj : any
83-
>`2${ 3 }4` : string
83+
>`2${ 3 }4` : "234"
8484
>3 : 3
8585

0 commit comments

Comments
 (0)