Skip to content

Commit 3dd68b8

Browse files
authored
Fix template literal type relations (microsoft#43440)
* Fix template literal relationships * Accept new baselines * Add regression test
1 parent 819651e commit 3dd68b8

File tree

6 files changed

+69
-27
lines changed

6 files changed

+69
-27
lines changed

src/compiler/checker.ts

+5-14
Original file line numberDiff line numberDiff line change
@@ -18274,6 +18274,11 @@ namespace ts {
1827418274
}
1827518275
}
1827618276
else if (target.flags & TypeFlags.TemplateLiteral) {
18277+
if (source.flags & TypeFlags.TemplateLiteral) {
18278+
// Report unreliable variance for type variables referenced in template literal type placeholders.
18279+
// For example, `foo-${number}` is related to `foo-${string}` even though number isn't related to string.
18280+
instantiateType(source, makeFunctionTypeMapper(reportUnreliableMarkers));
18281+
}
1827718282
const result = inferTypesFromTemplateLiteralType(source, target as TemplateLiteralType);
1827818283
if (result && every(result, (r, i) => isValidTypeForTemplateLiteralPlaceholder(r, (target as TemplateLiteralType).types[i]))) {
1827918284
return Ternary.True;
@@ -18318,20 +18323,6 @@ namespace ts {
1831818323
return result;
1831918324
}
1832018325
}
18321-
else if (source.flags & TypeFlags.TemplateLiteral) {
18322-
if (target.flags & TypeFlags.TemplateLiteral &&
18323-
(source as TemplateLiteralType).texts.length === (target as TemplateLiteralType).texts.length &&
18324-
(source as TemplateLiteralType).types.length === (target as TemplateLiteralType).types.length &&
18325-
every((source as TemplateLiteralType).texts, (t, i) => t === (target as TemplateLiteralType).texts[i]) &&
18326-
every((instantiateType(source, makeFunctionTypeMapper(reportUnreliableMarkers)) as TemplateLiteralType).types, (t, i) => !!((target as TemplateLiteralType).types[i].flags & (TypeFlags.Any | TypeFlags.String)) || !!isRelatedTo(t, (target as TemplateLiteralType).types[i], /*reportErrors*/ false))) {
18327-
return Ternary.True;
18328-
}
18329-
const constraint = getBaseConstraintOfType(source);
18330-
if (constraint && constraint !== source && (result = isRelatedTo(constraint, target, reportErrors))) {
18331-
resetErrorInfo(saveErrorInfo);
18332-
return result;
18333-
}
18334-
}
1833518326
else if (source.flags & TypeFlags.StringMapping) {
1833618327
if (target.flags & TypeFlags.StringMapping && (<StringMappingType>source).symbol === (<StringMappingType>target).symbol) {
1833718328
if (result = isRelatedTo((<StringMappingType>source).type, (<StringMappingType>target).type, reportErrors)) {

tests/baselines/reference/templateLiteralTypes2.errors.txt

+7-13
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(23,11): error TS2322: Type 'string' is not assignable to type '`abc${string}`'.
22
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(29,11): error TS2322: Type 'string' is not assignable to type '`foo${string}` | `bar${string}`'.
33
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(32,11): error TS2322: Type 'string' is not assignable to type '`foo${string}` | `bar${string}` | `baz${string}`'.
4-
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(67,9): error TS2322: Type '`foo${number}`' is not assignable to type 'String'.
5-
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(68,9): error TS2322: Type '`foo${number}`' is not assignable to type 'Object'.
6-
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(69,9): error TS2322: Type '`foo${number}`' is not assignable to type '{}'.
7-
tests/cases/conformance/types/literal/templateLiteralTypes2.ts(70,9): error TS2322: Type '`foo${number}`' is not assignable to type '{ length: number; }'.
84

95

10-
==== tests/cases/conformance/types/literal/templateLiteralTypes2.ts (7 errors) ====
6+
==== tests/cases/conformance/types/literal/templateLiteralTypes2.ts (3 errors) ====
117
function ft1<T extends string>(s: string, n: number, u: 'foo' | 'bar' | 'baz', t: T) {
128
const c1 = `abc${s}`; // `abc${string}`
139
const c2 = `abc${n}`; // `abc${number}`
@@ -81,17 +77,9 @@ tests/cases/conformance/types/literal/templateLiteralTypes2.ts(70,9): error TS23
8177
function ft14(t: `foo${number}`) {
8278
let x1: string = t;
8379
let x2: String = t;
84-
~~
85-
!!! error TS2322: Type '`foo${number}`' is not assignable to type 'String'.
8680
let x3: Object = t;
87-
~~
88-
!!! error TS2322: Type '`foo${number}`' is not assignable to type 'Object'.
8981
let x4: {} = t;
90-
~~
91-
!!! error TS2322: Type '`foo${number}`' is not assignable to type '{}'.
9282
let x6: { length: number } = t;
93-
~~
94-
!!! error TS2322: Type '`foo${number}`' is not assignable to type '{ length: number; }'.
9583
}
9684

9785
declare function g1<T>(x: T): T;
@@ -134,4 +122,10 @@ tests/cases/conformance/types/literal/templateLiteralTypes2.ts(70,9): error TS23
134122
function getCardTitle(title: string): `test-${string}` {
135123
return `test-${title}`;
136124
}
125+
126+
// Repro from #43424
127+
128+
const interpolatedStyle = { rotate: 12 };
129+
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
130+
C2(`rotate(${interpolatedStyle.rotate}dig)`);
137131

tests/baselines/reference/templateLiteralTypes2.js

+14
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;
111111
function getCardTitle(title: string): `test-${string}` {
112112
return `test-${title}`;
113113
}
114+
115+
// Repro from #43424
116+
117+
const interpolatedStyle = { rotate: 12 };
118+
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
119+
C2(`rotate(${interpolatedStyle.rotate}dig)`);
114120

115121

116122
//// [templateLiteralTypes2.js]
@@ -194,6 +200,10 @@ var pixelStringWithTemplate = pixelValue + "px";
194200
function getCardTitle(title) {
195201
return "test-" + title;
196202
}
203+
// Repro from #43424
204+
var interpolatedStyle = { rotate: 12 };
205+
function C2(transform) { return 12; }
206+
C2("rotate(" + interpolatedStyle.rotate + "dig)");
197207

198208

199209
//// [templateLiteralTypes2.d.ts]
@@ -225,3 +235,7 @@ declare type PixelValueType = `${number}px`;
225235
declare const pixelString: PixelValueType;
226236
declare const pixelStringWithTemplate: PixelValueType;
227237
declare function getCardTitle(title: string): `test-${string}`;
238+
declare const interpolatedStyle: {
239+
rotate: number;
240+
};
241+
declare function C2(transform: "-moz-initial" | (string & {})): number;

tests/baselines/reference/templateLiteralTypes2.symbols

+16
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,19 @@ function getCardTitle(title: string): `test-${string}` {
361361
>title : Symbol(title, Decl(templateLiteralTypes2.ts, 109, 22))
362362
}
363363

364+
// Repro from #43424
365+
366+
const interpolatedStyle = { rotate: 12 };
367+
>interpolatedStyle : Symbol(interpolatedStyle, Decl(templateLiteralTypes2.ts, 115, 5))
368+
>rotate : Symbol(rotate, Decl(templateLiteralTypes2.ts, 115, 27))
369+
370+
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
371+
>C2 : Symbol(C2, Decl(templateLiteralTypes2.ts, 115, 41))
372+
>transform : Symbol(transform, Decl(templateLiteralTypes2.ts, 116, 12))
373+
374+
C2(`rotate(${interpolatedStyle.rotate}dig)`);
375+
>C2 : Symbol(C2, Decl(templateLiteralTypes2.ts, 115, 41))
376+
>interpolatedStyle.rotate : Symbol(rotate, Decl(templateLiteralTypes2.ts, 115, 27))
377+
>interpolatedStyle : Symbol(interpolatedStyle, Decl(templateLiteralTypes2.ts, 115, 5))
378+
>rotate : Symbol(rotate, Decl(templateLiteralTypes2.ts, 115, 27))
379+

tests/baselines/reference/templateLiteralTypes2.types

+21
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,24 @@ function getCardTitle(title: string): `test-${string}` {
392392
>title : string
393393
}
394394

395+
// Repro from #43424
396+
397+
const interpolatedStyle = { rotate: 12 };
398+
>interpolatedStyle : { rotate: number; }
399+
>{ rotate: 12 } : { rotate: number; }
400+
>rotate : number
401+
>12 : 12
402+
403+
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
404+
>C2 : (transform: "-moz-initial" | (string & {})) => number
405+
>transform : (string & {}) | "-moz-initial"
406+
>12 : 12
407+
408+
C2(`rotate(${interpolatedStyle.rotate}dig)`);
409+
>C2(`rotate(${interpolatedStyle.rotate}dig)`) : number
410+
>C2 : (transform: (string & {}) | "-moz-initial") => number
411+
>`rotate(${interpolatedStyle.rotate}dig)` : `rotate(${number}dig)`
412+
>interpolatedStyle.rotate : number
413+
>interpolatedStyle : { rotate: number; }
414+
>rotate : number
415+

tests/cases/conformance/types/literal/templateLiteralTypes2.ts

+6
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,9 @@ const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;
113113
function getCardTitle(title: string): `test-${string}` {
114114
return `test-${title}`;
115115
}
116+
117+
// Repro from #43424
118+
119+
const interpolatedStyle = { rotate: 12 };
120+
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
121+
C2(`rotate(${interpolatedStyle.rotate}dig)`);

0 commit comments

Comments
 (0)