Skip to content

Commit

Permalink
Fix constant evaluation of template string expressions (#58500)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahejlsberg committed May 14, 2024
1 parent e51cbc8 commit d90e8e7
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 2 deletions.
7 changes: 5 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39560,11 +39560,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
texts.push(span.literal.text);
types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType);
}
const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluate(node).value;
if (evaluated) {
return getFreshTypeOfLiteralType(getStringLiteralType(evaluated));
}
if (isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType)) {
return getTemplateLiteralType(texts, types);
}
const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluate(node).value;
return evaluated ? getFreshTypeOfLiteralType(getStringLiteralType(evaluated)) : stringType;
return stringType;
}

function isTemplateLiteralContextualType(type: Type): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//// [tests/cases/compiler/templateLiteralConstantEvaluation.ts] ////

=== templateLiteralConstantEvaluation.ts ===
// https://github.com/microsoft/TypeScript/issues/58494

function fn<T>(arg: T): T {
>fn : Symbol(fn, Decl(templateLiteralConstantEvaluation.ts, 0, 0))
>T : Symbol(T, Decl(templateLiteralConstantEvaluation.ts, 2, 12))
>arg : Symbol(arg, Decl(templateLiteralConstantEvaluation.ts, 2, 15))
>T : Symbol(T, Decl(templateLiteralConstantEvaluation.ts, 2, 12))
>T : Symbol(T, Decl(templateLiteralConstantEvaluation.ts, 2, 12))

return arg;
>arg : Symbol(arg, Decl(templateLiteralConstantEvaluation.ts, 2, 15))
}

const a = '1';
>a : Symbol(a, Decl(templateLiteralConstantEvaluation.ts, 6, 5))

const b = a + ' 2';
>b : Symbol(b, Decl(templateLiteralConstantEvaluation.ts, 7, 5))
>a : Symbol(a, Decl(templateLiteralConstantEvaluation.ts, 6, 5))

const c = `${b} 3`;
>c : Symbol(c, Decl(templateLiteralConstantEvaluation.ts, 8, 5))
>b : Symbol(b, Decl(templateLiteralConstantEvaluation.ts, 7, 5))

const d = `${b} 3` as const;
>d : Symbol(d, Decl(templateLiteralConstantEvaluation.ts, 9, 5))
>b : Symbol(b, Decl(templateLiteralConstantEvaluation.ts, 7, 5))
>const : Symbol(const)

fn(`${b} 3`);
>fn : Symbol(fn, Decl(templateLiteralConstantEvaluation.ts, 0, 0))
>b : Symbol(b, Decl(templateLiteralConstantEvaluation.ts, 7, 5))

60 changes: 60 additions & 0 deletions tests/baselines/reference/templateLiteralConstantEvaluation.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//// [tests/cases/compiler/templateLiteralConstantEvaluation.ts] ////

=== templateLiteralConstantEvaluation.ts ===
// https://github.com/microsoft/TypeScript/issues/58494

function fn<T>(arg: T): T {
>fn : <T>(arg: T) => T
> : ^ ^^ ^^ ^^^^^
>arg : T
> : ^

return arg;
>arg : T
> : ^
}

const a = '1';
>a : "1"
> : ^^^
>'1' : "1"
> : ^^^

const b = a + ' 2';
>b : string
> : ^^^^^^
>a + ' 2' : string
> : ^^^^^^
>a : "1"
> : ^^^
>' 2' : " 2"
> : ^^^^

const c = `${b} 3`;
>c : "1 2 3"
> : ^^^^^^^
>`${b} 3` : "1 2 3"
> : ^^^^^^^
>b : string
> : ^^^^^^

const d = `${b} 3` as const;
>d : "1 2 3"
> : ^^^^^^^
>`${b} 3` as const : "1 2 3"
> : ^^^^^^^
>`${b} 3` : "1 2 3"
> : ^^^^^^^
>b : string
> : ^^^^^^

fn(`${b} 3`);
>fn(`${b} 3`) : "1 2 3"
> : ^^^^^^^
>fn : <T>(arg: T) => T
> : ^ ^^ ^^ ^^^^^^
>`${b} 3` : "1 2 3"
> : ^^^^^^^
>b : string
> : ^^^^^^

15 changes: 15 additions & 0 deletions tests/cases/compiler/templateLiteralConstantEvaluation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @strict: true
// @noEmit: true

// https://github.com/microsoft/TypeScript/issues/58494

function fn<T>(arg: T): T {
return arg;
}

const a = '1';
const b = a + ' 2';
const c = `${b} 3`;
const d = `${b} 3` as const;

fn(`${b} 3`);

0 comments on commit d90e8e7

Please sign in to comment.