Skip to content

Commit

Permalink
Remove string literals from unions with matching template literals (#…
Browse files Browse the repository at this point in the history
…41276)

* Remove string literals from unions with matching template literals

* Add tests

* Accept new baselines
  • Loading branch information
ahejlsberg authored Oct 27, 2020
1 parent 71cd5d5 commit 40b8122
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

15 changes: 15 additions & 0 deletions tests/baselines/reference/templateLiteralTypesPatterns.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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;
17 changes: 17 additions & 0 deletions tests/baselines/reference/templateLiteralTypesPatterns.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -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))

17 changes: 17 additions & 0 deletions tests/baselines/reference/templateLiteralTypesPatterns.types
Original file line number Diff line number Diff line change
Expand Up @@ -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}`

Original file line number Diff line number Diff line change
Expand Up @@ -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';

0 comments on commit 40b8122

Please sign in to comment.