Template literal types for contextually typed template literal expressions (#43376)

* Template literal types for contextually typed template literal expressions

* Accept new baselines

* Add regression test

* Add a few more tests
This commit is contained in:
Anders Hejlsberg
2021-03-26 10:32:05 -07:00
committed by GitHub
parent b34e705672
commit a26acf4540
9 changed files with 199 additions and 87 deletions

View File

@@ -31824,7 +31824,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 {

View File

@@ -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`;

View File

@@ -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"

View File

@@ -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

View File

@@ -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) {
@@ -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}`
~~
@@ -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;
@@ -113,6 +94,14 @@ tests/cases/conformance/types/literal/templateLiteralTypes2.ts(98,7): error TS23
!!! error TS2322: Type '`foo${number}`' is not assignable to type '{ length: number; }'.
}
declare function g1<T>(x: T): T;
declare function g2<T extends string>(x: T): T;
function ft20(s: string) {
let x1 = g1(`xyz-${s}`); // string
let x2 = g2(`xyz-${s}`); // `xyz-${string}`
}
// Repro from #41631
declare function takesLiteral<T extends string>(literal: T): T extends `foo.bar.${infer R}` ? R : unknown;
@@ -139,6 +128,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}`;
}

View File

@@ -71,6 +71,14 @@ function ft14(t: `foo${number}`) {
let x6: { length: number } = t;
}
declare function g1<T>(x: T): T;
declare function g2<T extends string>(x: T): T;
function ft20(s: string) {
let x1 = g1(`xyz-${s}`); // string
let x2 = g2(`xyz-${s}`); // `xyz-${string}`
}
// Repro from #41631
declare function takesLiteral<T extends string>(literal: T): T extends `foo.bar.${infer R}` ? R : unknown;
@@ -97,6 +105,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]
@@ -161,6 +175,10 @@ function ft14(t) {
var x4 = t;
var x6 = t;
}
function ft20(s) {
var x1 = g1("xyz-" + s); // string
var x2 = g2("xyz-" + s); // `xyz-${string}`
}
var t1 = takesLiteral("foo.bar.baz"); // "baz"
var id2 = "foo.bar.baz";
var t2 = takesLiteral(id2); // "baz"
@@ -172,6 +190,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]
@@ -185,17 +207,21 @@ declare function nonWidening<T extends string | number | symbol>(x: T): T;
declare function ft13(s: string, cond: boolean): void;
declare type T0 = string | `${number}px`;
declare function ft14(t: `foo${number}`): void;
declare function g1<T>(x: T): T;
declare function g2<T extends string>(x: T): T;
declare function ft20(s: string): void;
declare function takesLiteral<T extends string>(literal: T): T extends `foo.bar.${infer R}` ? R : unknown;
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}`;

View File

@@ -257,68 +257,107 @@ function ft14(t: `foo${number}`) {
>t : Symbol(t, Decl(templateLiteralTypes2.ts, 64, 14))
}
declare function g1<T>(x: T): T;
>g1 : Symbol(g1, Decl(templateLiteralTypes2.ts, 70, 1))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 72, 20))
>x : Symbol(x, Decl(templateLiteralTypes2.ts, 72, 23))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 72, 20))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 72, 20))
declare function g2<T extends string>(x: T): T;
>g2 : Symbol(g2, Decl(templateLiteralTypes2.ts, 72, 32))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 73, 20))
>x : Symbol(x, Decl(templateLiteralTypes2.ts, 73, 38))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 73, 20))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 73, 20))
function ft20(s: string) {
>ft20 : Symbol(ft20, Decl(templateLiteralTypes2.ts, 73, 47))
>s : Symbol(s, Decl(templateLiteralTypes2.ts, 75, 14))
let x1 = g1(`xyz-${s}`); // string
>x1 : Symbol(x1, Decl(templateLiteralTypes2.ts, 76, 7))
>g1 : Symbol(g1, Decl(templateLiteralTypes2.ts, 70, 1))
>s : Symbol(s, Decl(templateLiteralTypes2.ts, 75, 14))
let x2 = g2(`xyz-${s}`); // `xyz-${string}`
>x2 : Symbol(x2, Decl(templateLiteralTypes2.ts, 77, 7))
>g2 : Symbol(g2, Decl(templateLiteralTypes2.ts, 72, 32))
>s : Symbol(s, Decl(templateLiteralTypes2.ts, 75, 14))
}
// Repro from #41631
declare function takesLiteral<T extends string>(literal: T): T extends `foo.bar.${infer R}` ? R : unknown;
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 70, 1))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 74, 30))
>literal : Symbol(literal, Decl(templateLiteralTypes2.ts, 74, 48))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 74, 30))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 74, 30))
>R : Symbol(R, Decl(templateLiteralTypes2.ts, 74, 87))
>R : Symbol(R, Decl(templateLiteralTypes2.ts, 74, 87))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 78, 1))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 82, 30))
>literal : Symbol(literal, Decl(templateLiteralTypes2.ts, 82, 48))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 82, 30))
>T : Symbol(T, Decl(templateLiteralTypes2.ts, 82, 30))
>R : Symbol(R, Decl(templateLiteralTypes2.ts, 82, 87))
>R : Symbol(R, Decl(templateLiteralTypes2.ts, 82, 87))
const t1 = takesLiteral("foo.bar.baz"); // "baz"
>t1 : Symbol(t1, Decl(templateLiteralTypes2.ts, 76, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 70, 1))
>t1 : Symbol(t1, Decl(templateLiteralTypes2.ts, 84, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 78, 1))
const id2 = "foo.bar.baz";
>id2 : Symbol(id2, Decl(templateLiteralTypes2.ts, 77, 5))
>id2 : Symbol(id2, Decl(templateLiteralTypes2.ts, 85, 5))
const t2 = takesLiteral(id2); // "baz"
>t2 : Symbol(t2, Decl(templateLiteralTypes2.ts, 78, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 70, 1))
>id2 : Symbol(id2, Decl(templateLiteralTypes2.ts, 77, 5))
>t2 : Symbol(t2, Decl(templateLiteralTypes2.ts, 86, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 78, 1))
>id2 : Symbol(id2, Decl(templateLiteralTypes2.ts, 85, 5))
declare const someString: string;
>someString : Symbol(someString, Decl(templateLiteralTypes2.ts, 80, 13))
>someString : Symbol(someString, Decl(templateLiteralTypes2.ts, 88, 13))
const t3 = takesLiteral(`foo.bar.${someString}`); // string
>t3 : Symbol(t3, Decl(templateLiteralTypes2.ts, 81, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 70, 1))
>someString : Symbol(someString, Decl(templateLiteralTypes2.ts, 80, 13))
>t3 : Symbol(t3, Decl(templateLiteralTypes2.ts, 89, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 78, 1))
>someString : Symbol(someString, Decl(templateLiteralTypes2.ts, 88, 13))
const id4 = `foo.bar.${someString}`;
>id4 : Symbol(id4, Decl(templateLiteralTypes2.ts, 83, 5))
>someString : Symbol(someString, Decl(templateLiteralTypes2.ts, 80, 13))
>id4 : Symbol(id4, Decl(templateLiteralTypes2.ts, 91, 5))
>someString : Symbol(someString, Decl(templateLiteralTypes2.ts, 88, 13))
const t4 = takesLiteral(id4); // string
>t4 : Symbol(t4, Decl(templateLiteralTypes2.ts, 84, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 70, 1))
>id4 : Symbol(id4, Decl(templateLiteralTypes2.ts, 83, 5))
>t4 : Symbol(t4, Decl(templateLiteralTypes2.ts, 92, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 78, 1))
>id4 : Symbol(id4, Decl(templateLiteralTypes2.ts, 91, 5))
declare const someUnion: 'abc' | 'def' | 'ghi';
>someUnion : Symbol(someUnion, Decl(templateLiteralTypes2.ts, 86, 13))
>someUnion : Symbol(someUnion, Decl(templateLiteralTypes2.ts, 94, 13))
const t5 = takesLiteral(`foo.bar.${someUnion}`); // "abc" | "def" | "ghi"
>t5 : Symbol(t5, Decl(templateLiteralTypes2.ts, 87, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 70, 1))
>someUnion : Symbol(someUnion, Decl(templateLiteralTypes2.ts, 86, 13))
>t5 : Symbol(t5, Decl(templateLiteralTypes2.ts, 95, 5))
>takesLiteral : Symbol(takesLiteral, Decl(templateLiteralTypes2.ts, 78, 1))
>someUnion : Symbol(someUnion, Decl(templateLiteralTypes2.ts, 94, 13))
// Repro from #41732
const pixelValue: number = 22;
>pixelValue : Symbol(pixelValue, Decl(templateLiteralTypes2.ts, 91, 5))
>pixelValue : Symbol(pixelValue, Decl(templateLiteralTypes2.ts, 99, 5))
type PixelValueType = `${number}px`;
>PixelValueType : Symbol(PixelValueType, Decl(templateLiteralTypes2.ts, 91, 30))
>PixelValueType : Symbol(PixelValueType, Decl(templateLiteralTypes2.ts, 99, 30))
const pixelString: PixelValueType = `22px`;
>pixelString : Symbol(pixelString, Decl(templateLiteralTypes2.ts, 95, 5))
>PixelValueType : Symbol(PixelValueType, Decl(templateLiteralTypes2.ts, 91, 30))
>pixelString : Symbol(pixelString, Decl(templateLiteralTypes2.ts, 103, 5))
>PixelValueType : Symbol(PixelValueType, Decl(templateLiteralTypes2.ts, 99, 30))
const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;
>pixelStringWithTemplate : Symbol(pixelStringWithTemplate, Decl(templateLiteralTypes2.ts, 97, 5))
>PixelValueType : Symbol(PixelValueType, Decl(templateLiteralTypes2.ts, 91, 30))
>pixelValue : Symbol(pixelValue, Decl(templateLiteralTypes2.ts, 91, 5))
>pixelStringWithTemplate : Symbol(pixelStringWithTemplate, Decl(templateLiteralTypes2.ts, 105, 5))
>PixelValueType : Symbol(PixelValueType, Decl(templateLiteralTypes2.ts, 99, 30))
>pixelValue : Symbol(pixelValue, Decl(templateLiteralTypes2.ts, 99, 5))
// Repro from #43143
function getCardTitle(title: string): `test-${string}` {
>getCardTitle : Symbol(getCardTitle, Decl(templateLiteralTypes2.ts, 105, 66))
>title : Symbol(title, Decl(templateLiteralTypes2.ts, 109, 22))
return `test-${title}`;
>title : Symbol(title, Decl(templateLiteralTypes2.ts, 109, 22))
}

View File

@@ -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
}
@@ -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}`
@@ -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;
@@ -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;
@@ -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;
@@ -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
}
@@ -283,6 +283,33 @@ function ft14(t: `foo${number}`) {
>t : `foo${number}`
}
declare function g1<T>(x: T): T;
>g1 : <T>(x: T) => T
>x : T
declare function g2<T extends string>(x: T): T;
>g2 : <T extends string>(x: T) => T
>x : T
function ft20(s: string) {
>ft20 : (s: string) => void
>s : string
let x1 = g1(`xyz-${s}`); // string
>x1 : string
>g1(`xyz-${s}`) : string
>g1 : <T>(x: T) => T
>`xyz-${s}` : string
>s : string
let x2 = g2(`xyz-${s}`); // `xyz-${string}`
>x2 : `xyz-${string}`
>g2(`xyz-${s}`) : `xyz-${string}`
>g2 : <T extends string>(x: T) => T
>`xyz-${s}` : `xyz-${string}`
>s : string
}
// Repro from #41631
declare function takesLiteral<T extends string>(literal: T): T extends `foo.bar.${infer R}` ? R : unknown;
@@ -309,10 +336,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}`;
@@ -330,10 +357,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
@@ -351,6 +378,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
}

View File

@@ -73,6 +73,14 @@ function ft14(t: `foo${number}`) {
let x6: { length: number } = t;
}
declare function g1<T>(x: T): T;
declare function g2<T extends string>(x: T): T;
function ft20(s: string) {
let x1 = g1(`xyz-${s}`); // string
let x2 = g2(`xyz-${s}`); // `xyz-${string}`
}
// Repro from #41631
declare function takesLiteral<T extends string>(literal: T): T extends `foo.bar.${infer R}` ? R : unknown;
@@ -99,3 +107,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}`;
}