Fix template literal type relations (#43440)

* Fix template literal relationships

* Accept new baselines

* Add regression test
This commit is contained in:
Anders Hejlsberg
2021-03-30 12:53:15 -10:00
committed by GitHub
parent 819651eb5f
commit 3dd68b878a
6 changed files with 69 additions and 27 deletions
+5 -14
View File
@@ -18274,6 +18274,11 @@ namespace ts {
}
}
else if (target.flags & TypeFlags.TemplateLiteral) {
if (source.flags & TypeFlags.TemplateLiteral) {
// Report unreliable variance for type variables referenced in template literal type placeholders.
// For example, `foo-${number}` is related to `foo-${string}` even though number isn't related to string.
instantiateType(source, makeFunctionTypeMapper(reportUnreliableMarkers));
}
const result = inferTypesFromTemplateLiteralType(source, target as TemplateLiteralType);
if (result && every(result, (r, i) => isValidTypeForTemplateLiteralPlaceholder(r, (target as TemplateLiteralType).types[i]))) {
return Ternary.True;
@@ -18318,20 +18323,6 @@ namespace ts {
return result;
}
}
else if (source.flags & TypeFlags.TemplateLiteral) {
if (target.flags & TypeFlags.TemplateLiteral &&
(source as TemplateLiteralType).texts.length === (target as TemplateLiteralType).texts.length &&
(source as TemplateLiteralType).types.length === (target as TemplateLiteralType).types.length &&
every((source as TemplateLiteralType).texts, (t, i) => t === (target as TemplateLiteralType).texts[i]) &&
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))) {
return Ternary.True;
}
const constraint = getBaseConstraintOfType(source);
if (constraint && constraint !== source && (result = isRelatedTo(constraint, target, reportErrors))) {
resetErrorInfo(saveErrorInfo);
return result;
}
}
else if (source.flags & TypeFlags.StringMapping) {
if (target.flags & TypeFlags.StringMapping && (<StringMappingType>source).symbol === (<StringMappingType>target).symbol) {
if (result = isRelatedTo((<StringMappingType>source).type, (<StringMappingType>target).type, reportErrors)) {
@@ -1,13 +1,9 @@
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(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 (7 errors) ====
==== tests/cases/conformance/types/literal/templateLiteralTypes2.ts (3 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}`
@@ -81,17 +77,9 @@ tests/cases/conformance/types/literal/templateLiteralTypes2.ts(70,9): error TS23
function ft14(t: `foo${number}`) {
let x1: string = t;
let x2: String = t;
~~
!!! error TS2322: Type '`foo${number}`' is not assignable to type 'String'.
let x3: Object = t;
~~
!!! error TS2322: Type '`foo${number}`' is not assignable to type 'Object'.
let x4: {} = t;
~~
!!! error TS2322: Type '`foo${number}`' is not assignable to type '{}'.
let x6: { length: number } = t;
~~
!!! error TS2322: Type '`foo${number}`' is not assignable to type '{ length: number; }'.
}
declare function g1<T>(x: T): T;
@@ -134,4 +122,10 @@ tests/cases/conformance/types/literal/templateLiteralTypes2.ts(70,9): error TS23
function getCardTitle(title: string): `test-${string}` {
return `test-${title}`;
}
// Repro from #43424
const interpolatedStyle = { rotate: 12 };
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
C2(`rotate(${interpolatedStyle.rotate}dig)`);
@@ -111,6 +111,12 @@ const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;
function getCardTitle(title: string): `test-${string}` {
return `test-${title}`;
}
// Repro from #43424
const interpolatedStyle = { rotate: 12 };
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
C2(`rotate(${interpolatedStyle.rotate}dig)`);
//// [templateLiteralTypes2.js]
@@ -194,6 +200,10 @@ var pixelStringWithTemplate = pixelValue + "px";
function getCardTitle(title) {
return "test-" + title;
}
// Repro from #43424
var interpolatedStyle = { rotate: 12 };
function C2(transform) { return 12; }
C2("rotate(" + interpolatedStyle.rotate + "dig)");
//// [templateLiteralTypes2.d.ts]
@@ -225,3 +235,7 @@ declare type PixelValueType = `${number}px`;
declare const pixelString: PixelValueType;
declare const pixelStringWithTemplate: PixelValueType;
declare function getCardTitle(title: string): `test-${string}`;
declare const interpolatedStyle: {
rotate: number;
};
declare function C2(transform: "-moz-initial" | (string & {})): number;
@@ -361,3 +361,19 @@ function getCardTitle(title: string): `test-${string}` {
>title : Symbol(title, Decl(templateLiteralTypes2.ts, 109, 22))
}
// Repro from #43424
const interpolatedStyle = { rotate: 12 };
>interpolatedStyle : Symbol(interpolatedStyle, Decl(templateLiteralTypes2.ts, 115, 5))
>rotate : Symbol(rotate, Decl(templateLiteralTypes2.ts, 115, 27))
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
>C2 : Symbol(C2, Decl(templateLiteralTypes2.ts, 115, 41))
>transform : Symbol(transform, Decl(templateLiteralTypes2.ts, 116, 12))
C2(`rotate(${interpolatedStyle.rotate}dig)`);
>C2 : Symbol(C2, Decl(templateLiteralTypes2.ts, 115, 41))
>interpolatedStyle.rotate : Symbol(rotate, Decl(templateLiteralTypes2.ts, 115, 27))
>interpolatedStyle : Symbol(interpolatedStyle, Decl(templateLiteralTypes2.ts, 115, 5))
>rotate : Symbol(rotate, Decl(templateLiteralTypes2.ts, 115, 27))
@@ -392,3 +392,24 @@ function getCardTitle(title: string): `test-${string}` {
>title : string
}
// Repro from #43424
const interpolatedStyle = { rotate: 12 };
>interpolatedStyle : { rotate: number; }
>{ rotate: 12 } : { rotate: number; }
>rotate : number
>12 : 12
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
>C2 : (transform: "-moz-initial" | (string & {})) => number
>transform : (string & {}) | "-moz-initial"
>12 : 12
C2(`rotate(${interpolatedStyle.rotate}dig)`);
>C2(`rotate(${interpolatedStyle.rotate}dig)`) : number
>C2 : (transform: (string & {}) | "-moz-initial") => number
>`rotate(${interpolatedStyle.rotate}dig)` : `rotate(${number}dig)`
>interpolatedStyle.rotate : number
>interpolatedStyle : { rotate: number; }
>rotate : number
@@ -113,3 +113,9 @@ const pixelStringWithTemplate: PixelValueType = `${pixelValue}px`;
function getCardTitle(title: string): `test-${string}` {
return `test-${title}`;
}
// Repro from #43424
const interpolatedStyle = { rotate: 12 };
function C2(transform: "-moz-initial" | (string & {})) { return 12; }
C2(`rotate(${interpolatedStyle.rotate}dig)`);