Remove string literals from unions with matching template literals (#41276)

* Remove string literals from unions with matching template literals

* Add tests

* Accept new baselines
This commit is contained in:
Anders Hejlsberg 2020-10-27 16:21:07 -07:00 committed by GitHub
parent 71cd5d522d
commit 40b81224f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 0 deletions

View File

@ -13108,6 +13108,20 @@ namespace ts {
}
}
function removeStringLiteralsMatchedByTemplateLiterals(types: Type[]) {
const templates = filter(types, isPatternLiteralType);
if (templates.length) {
let i = types.length;
while (i > 0) {
i--;
const t = types[i];
if (t.flags & TypeFlags.StringLiteral && some(templates, template => isTypeSubtypeOf(t, template))) {
orderedRemoveItemAt(types, i);
}
}
}
}
// We sort and deduplicate the constituent types based on object identity. If the subtypeReduction
// flag is specified we also reduce the constituent type set to only include types that aren't subtypes
// of other types. Subtype reduction is expensive for large union types and is possible only when union
@ -13133,6 +13147,9 @@ namespace ts {
if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol)) {
removeRedundantLiteralTypes(typeSet, includes);
}
if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) {
removeStringLiteralsMatchedByTemplateLiterals(typeSet);
}
break;
case UnionReduction.Subtype:
if (!removeSubtypes(typeSet, !(includes & TypeFlags.IncludesStructuredOrInstantiable))) {

View File

@ -338,4 +338,13 @@ tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts(160,7): er
var aa: '0';
var aa: '0' & `${number}`;
// Remove string literals from unions with matching template literals
let t1: `foo${string}` | 'foo1' | '1foo'; // `foo${string}` | '1foo'
let t2: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo'; // `foo${string}` | '1foo' | 'xfoo'
let t3: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo' | `${number}foo`; // `foo${string}` | xfoo' | `${number}foo`
var bb: `${number}`;
var bb: `${number}` | '0';

View File

@ -165,6 +165,15 @@ const exampleGood: B = "1 2"; // ok
var aa: '0';
var aa: '0' & `${number}`;
// Remove string literals from unions with matching template literals
let t1: `foo${string}` | 'foo1' | '1foo'; // `foo${string}` | '1foo'
let t2: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo'; // `foo${string}` | '1foo' | 'xfoo'
let t3: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo' | `${number}foo`; // `foo${string}` | xfoo' | `${number}foo`
var bb: `${number}`;
var bb: `${number}` | '0';
//// [templateLiteralTypesPatterns.js]
@ -289,3 +298,9 @@ var exampleGood = "1 2"; // ok
// Repro from #41161
var aa;
var aa;
// Remove string literals from unions with matching template literals
var t1; // `foo${string}` | '1foo'
var t2; // `foo${string}` | '1foo' | 'xfoo'
var t3; // `foo${string}` | xfoo' | `${number}foo`
var bb;
var bb;

View File

@ -401,3 +401,20 @@ var aa: '0';
var aa: '0' & `${number}`;
>aa : Symbol(aa, Decl(templateLiteralTypesPatterns.ts, 164, 3), Decl(templateLiteralTypesPatterns.ts, 165, 3))
// Remove string literals from unions with matching template literals
let t1: `foo${string}` | 'foo1' | '1foo'; // `foo${string}` | '1foo'
>t1 : Symbol(t1, Decl(templateLiteralTypesPatterns.ts, 169, 3))
let t2: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo'; // `foo${string}` | '1foo' | 'xfoo'
>t2 : Symbol(t2, Decl(templateLiteralTypesPatterns.ts, 170, 3))
let t3: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo' | `${number}foo`; // `foo${string}` | xfoo' | `${number}foo`
>t3 : Symbol(t3, Decl(templateLiteralTypesPatterns.ts, 171, 3))
var bb: `${number}`;
>bb : Symbol(bb, Decl(templateLiteralTypesPatterns.ts, 173, 3), Decl(templateLiteralTypesPatterns.ts, 174, 3))
var bb: `${number}` | '0';
>bb : Symbol(bb, Decl(templateLiteralTypesPatterns.ts, 173, 3), Decl(templateLiteralTypesPatterns.ts, 174, 3))

View File

@ -560,3 +560,20 @@ var aa: '0';
var aa: '0' & `${number}`;
>aa : "0"
// Remove string literals from unions with matching template literals
let t1: `foo${string}` | 'foo1' | '1foo'; // `foo${string}` | '1foo'
>t1 : `foo${string}` | "1foo"
let t2: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo'; // `foo${string}` | '1foo' | 'xfoo'
>t2 : `foo${string}` | "1foo" | "xfoo"
let t3: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo' | `${number}foo`; // `foo${string}` | xfoo' | `${number}foo`
>t3 : `foo${string}` | "xfoo" | `${number}foo`
var bb: `${number}`;
>bb : `${number}`
var bb: `${number}` | '0';
>bb : `${number}`

View File

@ -165,3 +165,12 @@ const exampleGood: B = "1 2"; // ok
var aa: '0';
var aa: '0' & `${number}`;
// Remove string literals from unions with matching template literals
let t1: `foo${string}` | 'foo1' | '1foo'; // `foo${string}` | '1foo'
let t2: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo'; // `foo${string}` | '1foo' | 'xfoo'
let t3: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo' | `${number}foo`; // `foo${string}` | xfoo' | `${number}foo`
var bb: `${number}`;
var bb: `${number}` | '0';