Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13100,6 +13100,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 @@ -13125,6 +13139,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';