Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31799,7 +31799,12 @@ namespace ts {
texts.push(span.literal.text);
types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType);
}
return isConstContext(node) ? getTemplateLiteralType(texts, types) : stringType;
return isConstContext(node) || someType(getContextualType(node) || unknownType, isTemplateLiteralContextualType) ? getTemplateLiteralType(texts, types) : stringType;
}

function isTemplateLiteralContextualType(type: Type): boolean {
return !!(type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral) ||
type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike));
}

function getContextNode(node: Expression): Node {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
tests/cases/conformance/types/stringLiteral/stringLiteralTypesWithTemplateStrings02.ts(1,5): error TS2322: Type '"AB\nC"' is not assignable to type '"AB\r\nC"'.
tests/cases/conformance/types/stringLiteral/stringLiteralTypesWithTemplateStrings02.ts(3,5): error TS2322: Type 'string' is not assignable to type '"DE\nF"'.


==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesWithTemplateStrings02.ts (2 errors) ====
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesWithTemplateStrings02.ts (1 errors) ====
let abc: "AB\r\nC" = `AB
~~~
!!! error TS2322: Type '"AB\nC"' is not assignable to type '"AB\r\nC"'.
C`;
let de_NEWLINE_f: "DE\nF" = `DE${"\n"}F`;
~~~~~~~~~~~~
!!! error TS2322: Type 'string' is not assignable to type '"DE\nF"'.
let de_NEWLINE_f: "DE\nF" = `DE${"\n"}F`;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ let abc: "AB\r\nC" = `AB
C`;
let de_NEWLINE_f: "DE\nF" = `DE${"\n"}F`;
>de_NEWLINE_f : "DE\nF"
>`DE${"\n"}F` : string
>`DE${"\n"}F` : "DE\nF"
>"\n" : "\n"

2 changes: 1 addition & 1 deletion tests/baselines/reference/templateLiteralTypes1.types
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const createScopedActionType = <S extends string>(scope: S) => <T extends string
><T extends string>(type: T) => `${scope}/${type}` as `${S}/${T}` : <T extends string>(type: T) => `${S}/${T}`
>type : T
>`${scope}/${type}` as `${S}/${T}` : `${S}/${T}`
>`${scope}/${type}` : string
>`${scope}/${type}` : `${S}/${T}`
>scope : S
>type : T

Expand Down
29 changes: 7 additions & 22 deletions tests/baselines/reference/templateLiteralTypes2.errors.txt
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(6,11): error TS2322: Type 'string' is not assignable to type '`abc${string}`'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(7,11): error TS2322: Type 'string' is not assignable to type '`abc${number}`'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(8,11): error TS2322: Type 'string' is not assignable to type '"abcfoo" | "abcbar" | "abcbaz"'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(9,11): error TS2322: Type 'string' is not assignable to type '`abc${T}`'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(21,11): error TS2322: Type 'string' is not assignable to type '`abc${string}`'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(23,11): error TS2322: Type 'string' is not assignable to type '`abc${string}`'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(29,11): error TS2322: Type 'string' is not assignable to type '`foo${string}` | `bar${string}`'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(32,11): error TS2322: Type 'string' is not assignable to type '`foo${string}` | `bar${string}` | `baz${string}`'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(43,11): error TS2322: Type 'string' is not assignable to type '`foo${string}`'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(67,9): error TS2322: Type '`foo${number}`' is not assignable to type 'String'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(68,9): error TS2322: Type '`foo${number}`' is not assignable to type 'Object'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(69,9): error TS2322: Type '`foo${number}`' is not assignable to type '{}'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(70,9): error TS2322: Type '`foo${number}`' is not assignable to type '{ length: number; }'.
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(98,7): error TS2322: Type 'string' is not assignable to type '`${number}px`'.


==== tests/cases/conformance/types/literal/templateLiteralTypes2.ts (14 errors) ====
==== tests/cases/conformance/types/literal/templateLiteralTypes2.ts (7 errors) ====
function ft1<T extends string>(s: string, n: number, u: 'foo' | 'bar' | 'baz', t: T) {
const c1 = `abc${s}`; // `abc${string}`
const c2 = `abc${n}`; // `abc${number}`
const c3 = `abc${u}`; // "abcfoo" | "abcbar" | "abcbaz"
const c4 = `abc${t}`; // `abc${T}
const d1: `abc${string}` = `abc${s}`;
~~
!!! error TS2322: Type 'string' is not assignable to type '`abc${string}`'.
const d2: `abc${number}` = `abc${n}`;
~~
!!! error TS2322: Type 'string' is not assignable to type '`abc${number}`'.
const d3: `abc${'foo' | 'bar' | 'baz'}` = `abc${u}`;
~~
!!! error TS2322: Type 'string' is not assignable to type '"abcfoo" | "abcbar" | "abcbaz"'.
const d4: `abc${T}` = `abc${t}`;
~~
!!! error TS2322: Type 'string' is not assignable to type '`abc${T}`'.
}

function ft2(s: string) {
Expand All @@ -44,8 +29,6 @@ tests/cases/conformance/types/literal/templateLiteralTypes2.ts(98,7): error TS23
const c2 = c1; // Widening type `abc${string}`
let v2 = c2; // Type string
const c3: `abc${string}` = `abc${s}`;
~~
!!! error TS2322: Type 'string' is not assignable to type '`abc${string}`'.
let v3 = c3; // Type `abc${string}`
const c4: `abc${string}` = c1; // Type `abc${string}`
~~
Expand Down Expand Up @@ -74,8 +57,6 @@ tests/cases/conformance/types/literal/templateLiteralTypes2.ts(98,7): error TS23
const c1 = `foo${s}`;
let v1 = c1;
const c2: `foo${string}` = `foo${s}`;
~~
!!! error TS2322: Type 'string' is not assignable to type '`foo${string}`'.
let v2 = c2;
const c3 = `foo${s}` as `foo${string}`;
let v3 = c3;
Expand Down Expand Up @@ -139,6 +120,10 @@ tests/cases/conformance/types/literal/templateLiteralTypes2.ts(98,7): error TS23
const pixelString: PixelValueType = `22px`;

const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;
~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'string' is not assignable to type '`${number}px`'.

// Repro from #43143

function getCardTitle(title: string): `test-${string}` {
return `test-${title}`;
}

15 changes: 13 additions & 2 deletions tests/baselines/reference/templateLiteralTypes2.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ type PixelValueType = `${number}px`;
const pixelString: PixelValueType = `22px`;

const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;

// Repro from #43143

function getCardTitle(title: string): `test-${string}` {
return `test-${title}`;
}


//// [templateLiteralTypes2.js]
Expand Down Expand Up @@ -172,6 +178,10 @@ var t5 = takesLiteral("foo.bar." + someUnion); // "abc" | "def" | "ghi"
var pixelValue = 22;
var pixelString = "22px";
var pixelStringWithTemplate = pixelValue + "px";
// Repro from #43143
function getCardTitle(title) {
return "test-" + title;
}


//// [templateLiteralTypes2.d.ts]
Expand All @@ -190,12 +200,13 @@ declare const t1: "baz";
declare const id2 = "foo.bar.baz";
declare const t2: "baz";
declare const someString: string;
declare const t3: unknown;
declare const t3: string;
declare const id4: string;
declare const t4: unknown;
declare const someUnion: 'abc' | 'def' | 'ghi';
declare const t5: unknown;
declare const t5: "abc" | "def" | "ghi";
declare const pixelValue: number;
declare type PixelValueType = `${number}px`;
declare const pixelString: PixelValueType;
declare const pixelStringWithTemplate: PixelValueType;
declare function getCardTitle(title: string): `test-${string}`;
10 changes: 10 additions & 0 deletions tests/baselines/reference/templateLiteralTypes2.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,13 @@ const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;
>PixelValueType : Symbol(PixelValueType, Decl(templateLiteralTypes2.ts, 91, 30))
>pixelValue : Symbol(pixelValue, Decl(templateLiteralTypes2.ts, 91, 5))

// Repro from #43143

function getCardTitle(title: string): `test-${string}` {
>getCardTitle : Symbol(getCardTitle, Decl(templateLiteralTypes2.ts, 97, 66))
>title : Symbol(title, Decl(templateLiteralTypes2.ts, 101, 22))

return `test-${title}`;
>title : Symbol(title, Decl(templateLiteralTypes2.ts, 101, 22))
}

55 changes: 33 additions & 22 deletions tests/baselines/reference/templateLiteralTypes2.types
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,22 @@ function ft1<T extends string>(s: string, n: number, u: 'foo' | 'bar' | 'baz', t

const d1: `abc${string}` = `abc${s}`;
>d1 : `abc${string}`
>`abc${s}` : string
>`abc${s}` : `abc${string}`
>s : string

const d2: `abc${number}` = `abc${n}`;
>d2 : `abc${number}`
>`abc${n}` : string
>`abc${n}` : `abc${number}`
>n : number

const d3: `abc${'foo' | 'bar' | 'baz'}` = `abc${u}`;
>d3 : "abcfoo" | "abcbar" | "abcbaz"
>`abc${u}` : string
>`abc${u}` : "abcfoo" | "abcbar" | "abcbaz"
>u : "foo" | "bar" | "baz"

const d4: `abc${T}` = `abc${t}`;
>d4 : `abc${T}`
>`abc${t}` : string
>`abc${t}` : `abc${T}`
>t : T
}

Expand Down Expand Up @@ -79,7 +79,7 @@ function ft10(s: string) {

const c3: `abc${string}` = `abc${s}`;
>c3 : `abc${string}`
>`abc${s}` : string
>`abc${s}` : `abc${string}`
>s : string

let v3 = c3; // Type `abc${string}`
Expand Down Expand Up @@ -168,7 +168,7 @@ function ft12(s: string) {

const c2: `foo${string}` = `foo${s}`;
>c2 : `foo${string}`
>`foo${s}` : string
>`foo${s}` : `foo${string}`
>s : string

let v2 = c2;
Expand All @@ -178,7 +178,7 @@ function ft12(s: string) {
const c3 = `foo${s}` as `foo${string}`;
>c3 : `foo${string}`
>`foo${s}` as `foo${string}` : `foo${string}`
>`foo${s}` : string
>`foo${s}` : `foo${string}`
>s : string

let v3 = c3;
Expand All @@ -188,7 +188,7 @@ function ft12(s: string) {
const c4 = <`foo${string}`>`foo${s}`;
>c4 : `foo${string}`
><`foo${string}`>`foo${s}` : `foo${string}`
>`foo${s}` : string
>`foo${s}` : `foo${string}`
>s : string

let v4 = c4;
Expand Down Expand Up @@ -237,20 +237,20 @@ function ft13(s: string, cond: boolean) {
>s : string

let y1 = nonWidening(`foo${s}`);
>y1 : string
>nonWidening(`foo${s}`) : string
>y1 : `foo${string}`
>nonWidening(`foo${s}`) : `foo${string}`
>nonWidening : <T extends string | number | symbol>(x: T) => T
>`foo${s}` : string
>`foo${s}` : `foo${string}`
>s : string

let y2 = nonWidening(cond ? 'a' : `foo${s}`);
>y2 : string
>nonWidening(cond ? 'a' : `foo${s}`) : string
>y2 : `foo${string}` | "a"
>nonWidening(cond ? 'a' : `foo${s}`) : `foo${string}` | "a"
>nonWidening : <T extends string | number | symbol>(x: T) => T
>cond ? 'a' : `foo${s}` : string
>cond ? 'a' : `foo${s}` : `foo${string}` | "a"
>cond : boolean
>'a' : "a"
>`foo${s}` : string
>`foo${s}` : `foo${string}`
>s : string
}

Expand Down Expand Up @@ -309,10 +309,10 @@ declare const someString: string;
>someString : string

const t3 = takesLiteral(`foo.bar.${someString}`); // string
>t3 : unknown
>takesLiteral(`foo.bar.${someString}`) : unknown
>t3 : string
>takesLiteral(`foo.bar.${someString}`) : string
>takesLiteral : <T extends string>(literal: T) => T extends `foo.bar.${infer R}` ? R : unknown
>`foo.bar.${someString}` : string
>`foo.bar.${someString}` : `foo.bar.${string}`
>someString : string

const id4 = `foo.bar.${someString}`;
Expand All @@ -330,10 +330,10 @@ declare const someUnion: 'abc' | 'def' | 'ghi';
>someUnion : "abc" | "def" | "ghi"

const t5 = takesLiteral(`foo.bar.${someUnion}`); // "abc" | "def" | "ghi"
>t5 : unknown
>takesLiteral(`foo.bar.${someUnion}`) : unknown
>t5 : "abc" | "def" | "ghi"
>takesLiteral(`foo.bar.${someUnion}`) : "abc" | "def" | "ghi"
>takesLiteral : <T extends string>(literal: T) => T extends `foo.bar.${infer R}` ? R : unknown
>`foo.bar.${someUnion}` : string
>`foo.bar.${someUnion}` : "foo.bar.abc" | "foo.bar.def" | "foo.bar.ghi"
>someUnion : "abc" | "def" | "ghi"

// Repro from #41732
Expand All @@ -351,6 +351,17 @@ const pixelString: PixelValueType = `22px`;

const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;
>pixelStringWithTemplate : `${number}px`
>`${pixelValue}px` : string
>`${pixelValue}px` : `${number}px`
>pixelValue : number

// Repro from #43143

function getCardTitle(title: string): `test-${string}` {
>getCardTitle : (title: string) => `test-${string}`
>title : string

return `test-${title}`;
>`test-${title}` : `test-${string}`
>title : string
}

Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,9 @@ type PixelValueType = `${number}px`;
const pixelString: PixelValueType = `22px`;

const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;

// Repro from #43143

function getCardTitle(title: string): `test-${string}` {
return `test-${title}`;
}