diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0a98fd289a390..87cc0ca5b5f80 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 { diff --git a/tests/baselines/reference/stringLiteralTypesWithTemplateStrings02.errors.txt b/tests/baselines/reference/stringLiteralTypesWithTemplateStrings02.errors.txt index 4137661f0bef9..21293d7c84e6c 100644 --- a/tests/baselines/reference/stringLiteralTypesWithTemplateStrings02.errors.txt +++ b/tests/baselines/reference/stringLiteralTypesWithTemplateStrings02.errors.txt @@ -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"'. \ No newline at end of file + let de_NEWLINE_f: "DE\nF" = `DE${"\n"}F`; \ No newline at end of file diff --git a/tests/baselines/reference/stringLiteralTypesWithTemplateStrings02.types b/tests/baselines/reference/stringLiteralTypesWithTemplateStrings02.types index c8dcf901e534b..912ab642767ae 100644 --- a/tests/baselines/reference/stringLiteralTypesWithTemplateStrings02.types +++ b/tests/baselines/reference/stringLiteralTypesWithTemplateStrings02.types @@ -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" diff --git a/tests/baselines/reference/templateLiteralTypes1.types b/tests/baselines/reference/templateLiteralTypes1.types index 85ef5f05cd579..bc572e20bdc05 100644 --- a/tests/baselines/reference/templateLiteralTypes1.types +++ b/tests/baselines/reference/templateLiteralTypes1.types @@ -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 diff --git a/tests/baselines/reference/templateLiteralTypes2.errors.txt b/tests/baselines/reference/templateLiteralTypes2.errors.txt index f5e69d835636f..662b6704d6352 100644 --- a/tests/baselines/reference/templateLiteralTypes2.errors.txt +++ b/tests/baselines/reference/templateLiteralTypes2.errors.txt @@ -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}`; + } \ No newline at end of file diff --git a/tests/baselines/reference/templateLiteralTypes2.js b/tests/baselines/reference/templateLiteralTypes2.js index 3c9276c1eb009..87be2dbe4fa76 100644 --- a/tests/baselines/reference/templateLiteralTypes2.js +++ b/tests/baselines/reference/templateLiteralTypes2.js @@ -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}`; diff --git a/tests/baselines/reference/templateLiteralTypes2.symbols b/tests/baselines/reference/templateLiteralTypes2.symbols index 71dd7f21f4476..6348ebce7f95b 100644 --- a/tests/baselines/reference/templateLiteralTypes2.symbols +++ b/tests/baselines/reference/templateLiteralTypes2.symbols @@ -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)) +} diff --git a/tests/baselines/reference/templateLiteralTypes2.types b/tests/baselines/reference/templateLiteralTypes2.types index cb9d7ae2595a1..274e3eb4f0b1b 100644 --- a/tests/baselines/reference/templateLiteralTypes2.types +++ b/tests/baselines/reference/templateLiteralTypes2.types @@ -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 +} + diff --git a/tests/cases/conformance/types/literal/templateLiteralTypes2.ts b/tests/cases/conformance/types/literal/templateLiteralTypes2.ts index 248e0e5539a77..75ab1485a05fa 100644 --- a/tests/cases/conformance/types/literal/templateLiteralTypes2.ts +++ b/tests/cases/conformance/types/literal/templateLiteralTypes2.ts @@ -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}`; +}