Skip to content

Commit 02b5df0

Browse files
committed
Evaluate simple template expressions
1 parent 0c66314 commit 02b5df0

File tree

101 files changed

+688
-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.

101 files changed

+688
-535
lines changed

Diff for: src/compiler/checker.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -37302,7 +37302,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3730237302
texts.push(span.literal.text);
3730337303
types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType);
3730437304
}
37305-
return isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType) ? getTemplateLiteralType(texts, types) : stringType;
37305+
if (isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType)) {
37306+
return getTemplateLiteralType(texts, types);
37307+
}
37308+
const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluateTemplateExpression(node);
37309+
return evaluated ? getFreshTypeOfLiteralType(getStringLiteralType(evaluated)) : stringType;
3730637310
}
3730737311

3730837312
function isTemplateLiteralContextualType(type: Type): boolean {
@@ -43579,7 +43583,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4357943583
return value;
4358043584
}
4358143585

43582-
function evaluate(expr: Expression, location: Declaration): string | number | undefined {
43586+
function evaluate(expr: Expression, location?: Declaration): string | number | undefined {
4358343587
switch (expr.kind) {
4358443588
case SyntaxKind.PrefixUnaryExpression:
4358543589
const value = evaluate((expr as PrefixUnaryExpression).operand, location);
@@ -43636,11 +43640,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4363643640
const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true);
4363743641
if (symbol) {
4363843642
if (symbol.flags & SymbolFlags.EnumMember) {
43639-
return evaluateEnumMember(expr, symbol, location);
43643+
return location ? evaluateEnumMember(expr, symbol, location) : getEnumMemberValue(symbol.valueDeclaration as EnumMember);
4364043644
}
4364143645
if (isConstVariable(symbol)) {
4364243646
const declaration = symbol.valueDeclaration as VariableDeclaration | undefined;
43643-
if (declaration && !declaration.type && declaration.initializer && declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location)) {
43647+
if (declaration && !declaration.type && declaration.initializer && (!location || declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location))) {
4364443648
return evaluate(declaration.initializer, declaration);
4364543649
}
4364643650
}
@@ -43655,7 +43659,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4365543659
const name = escapeLeadingUnderscores(((expr as ElementAccessExpression).argumentExpression as StringLiteralLike).text);
4365643660
const member = rootSymbol.exports!.get(name);
4365743661
if (member) {
43658-
return evaluateEnumMember(expr, member, location);
43662+
return location ? evaluateEnumMember(expr, member, location) : getEnumMemberValue(member.valueDeclaration as EnumMember);
4365943663
}
4366043664
}
4366143665
}
@@ -43677,7 +43681,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4367743681
return getEnumMemberValue(declaration as EnumMember);
4367843682
}
4367943683

43680-
function evaluateTemplateExpression(expr: TemplateExpression, location: Declaration) {
43684+
function evaluateTemplateExpression(expr: TemplateExpression, location?: Declaration) {
4368143685
let result = expr.head.text;
4368243686
for (const span of expr.templateSpans) {
4368343687
const value = evaluate(span.expression, location);

Diff for: tests/baselines/reference/asOperator3.types

+2-2
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;

Diff for: tests/baselines/reference/classAttributeInferenceTemplate.types

+4-4
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
}

Diff for: tests/baselines/reference/classAttributeInferenceTemplateJS.types

+4-4
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
}
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+
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+

Diff for: tests/baselines/reference/enumConstantMemberWithTemplateLiterals.types

+1-1
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

Diff for: tests/baselines/reference/exponentiationOperatorWithTemplateStringInvalid.types

+12-12
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

Diff for: tests/baselines/reference/exponentiationOperatorWithTemplateStringInvalidES6.types

+12-12
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

Diff for: tests/baselines/reference/importCallExpressionShouldNotGetParen.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import(`./locales/${localeName}.js`).then(bar => {
77
>import(`./locales/${localeName}.js`).then(bar => { let x = bar;}) : Promise<void>
88
>import(`./locales/${localeName}.js`).then : <TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
99
>import(`./locales/${localeName}.js`) : Promise<any>
10-
>`./locales/${localeName}.js` : string
10+
>`./locales/${localeName}.js` : "./locales/zh-CN.js"
1111
>localeName : "zh-CN"
1212
>then : <TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
1313
>bar => { let x = bar;} : (bar: any) => void

0 commit comments

Comments
 (0)