Skip to content

Commit 57c8938

Browse files
authored
Consistent inferences when inferring to template literal type (microsoft#40518)
* Consistently make inferences when inferring to template literal type * Add tests * Accept new baselines
1 parent c9422e6 commit 57c8938

File tree

6 files changed

+209
-137
lines changed

6 files changed

+209
-137
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20056,14 +20056,12 @@ namespace ts {
2005620056
}
2005720057

2005820058
function inferToTemplateLiteralType(source: Type, target: TemplateLiteralType) {
20059-
if (source.flags & (TypeFlags.StringLike | TypeFlags.Index)) {
20060-
const matches = source.flags & TypeFlags.StringLiteral ? inferLiteralsFromTemplateLiteralType(<StringLiteralType>source, target) :
20061-
source.flags & TypeFlags.TemplateLiteral && arraysEqual((<TemplateLiteralType>source).texts, target.texts) && arraysEqual((<TemplateLiteralType>source).casings, target.casings)? (<TemplateLiteralType>source).types :
20062-
undefined;
20063-
const types = target.types;
20064-
for (let i = 0; i < types.length; i++) {
20065-
inferFromTypes(matches ? matches[i] : source.flags & TypeFlags.StringLiteral ? neverType : stringType, types[i]);
20066-
}
20059+
const matches = source.flags & TypeFlags.StringLiteral ? inferLiteralsFromTemplateLiteralType(<StringLiteralType>source, target) :
20060+
source.flags & TypeFlags.TemplateLiteral && arraysEqual((<TemplateLiteralType>source).texts, target.texts) && arraysEqual((<TemplateLiteralType>source).casings, target.casings)? (<TemplateLiteralType>source).types :
20061+
undefined;
20062+
const types = target.types;
20063+
for (let i = 0; i < types.length; i++) {
20064+
inferFromTypes(matches ? matches[i] : neverType, types[i]);
2006720065
}
2006820066
}
2006920067

tests/baselines/reference/templateLiteralTypes1.errors.txt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ tests/cases/conformance/types/literal/templateLiteralTypes1.ts(39,5): error TS23
55
Type 'string' is not assignable to type 'B'.
66
'string' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint 'string'.
77
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(165,15): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
8-
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(188,16): error TS2590: Expression produces a union type that is too complex to represent.
9-
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(192,16): error TS2590: Expression produces a union type that is too complex to represent.
10-
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(196,16): error TS2590: Expression produces a union type that is too complex to represent.
8+
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(197,16): error TS2590: Expression produces a union type that is too complex to represent.
9+
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(201,16): error TS2590: Expression produces a union type that is too complex to represent.
10+
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(205,16): error TS2590: Expression produces a union type that is too complex to represent.
1111

1212

1313
==== tests/cases/conformance/types/literal/templateLiteralTypes1.ts (6 errors) ====
@@ -198,6 +198,15 @@ tests/cases/conformance/types/literal/templateLiteralTypes1.ts(196,16): error TS
198198

199199
type L1 = Chars<'FooBarBazThisIsALongerString'>; // ['F', 'o', 'o', 'B', 'a', 'r', ...]
200200

201+
// Infer never when source isn't a literal type that matches the pattern
202+
203+
type Foo<T> = T extends `*${infer S}*` ? S : never;
204+
205+
type TF1 = Foo<any>; // never
206+
type TF2 = Foo<string>; // never
207+
type TF3 = Foo<'abc'>; // never
208+
type TF4 = Foo<'*abc*'>; // 'abc'
209+
201210
// Cross product unions limited to 100,000 constituents
202211

203212
type A = any;

tests/baselines/reference/templateLiteralTypes1.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,15 @@ type Chars<S extends string> =
176176

177177
type L1 = Chars<'FooBarBazThisIsALongerString'>; // ['F', 'o', 'o', 'B', 'a', 'r', ...]
178178

179+
// Infer never when source isn't a literal type that matches the pattern
180+
181+
type Foo<T> = T extends `*${infer S}*` ? S : never;
182+
183+
type TF1 = Foo<any>; // never
184+
type TF2 = Foo<string>; // never
185+
type TF3 = Foo<'abc'>; // never
186+
type TF4 = Foo<'*abc*'>; // 'abc'
187+
179188
// Cross product unions limited to 100,000 constituents
180189

181190
type A = any;
@@ -329,6 +338,11 @@ declare type S2<S extends string> = S;
329338
declare type TV1 = `${infer X}`;
330339
declare type Chars<S extends string> = string extends S ? string[] : S extends `${infer C0}${infer C1}${infer C2}${infer C3}${infer C4}${infer C5}${infer C6}${infer C7}${infer C8}${infer C9}${infer R}` ? [C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, ...Chars<R>] : S extends `${infer C}${infer R}` ? [C, ...Chars<R>] : S extends '' ? [] : never;
331340
declare type L1 = Chars<'FooBarBazThisIsALongerString'>;
341+
declare type Foo<T> = T extends `*${infer S}*` ? S : never;
342+
declare type TF1 = Foo<any>;
343+
declare type TF2 = Foo<string>;
344+
declare type TF3 = Foo<'abc'>;
345+
declare type TF4 = Foo<'*abc*'>;
332346
declare type A = any;
333347
declare type U1 = {
334348
a1: A;

0 commit comments

Comments
 (0)