Skip to content

Consistent inferences when inferring to template literal type #40518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 13, 2020
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
14 changes: 6 additions & 8 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20056,14 +20056,12 @@ namespace ts {
}

function inferToTemplateLiteralType(source: Type, target: TemplateLiteralType) {
if (source.flags & (TypeFlags.StringLike | TypeFlags.Index)) {
const matches = source.flags & TypeFlags.StringLiteral ? inferLiteralsFromTemplateLiteralType(<StringLiteralType>source, target) :
source.flags & TypeFlags.TemplateLiteral && arraysEqual((<TemplateLiteralType>source).texts, target.texts) && arraysEqual((<TemplateLiteralType>source).casings, target.casings)? (<TemplateLiteralType>source).types :
undefined;
const types = target.types;
for (let i = 0; i < types.length; i++) {
inferFromTypes(matches ? matches[i] : source.flags & TypeFlags.StringLiteral ? neverType : stringType, types[i]);
}
const matches = source.flags & TypeFlags.StringLiteral ? inferLiteralsFromTemplateLiteralType(<StringLiteralType>source, target) :
source.flags & TypeFlags.TemplateLiteral && arraysEqual((<TemplateLiteralType>source).texts, target.texts) && arraysEqual((<TemplateLiteralType>source).casings, target.casings)? (<TemplateLiteralType>source).types :
undefined;
const types = target.types;
for (let i = 0; i < types.length; i++) {
inferFromTypes(matches ? matches[i] : neverType, types[i]);
}
}

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


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

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

// Infer never when source isn't a literal type that matches the pattern

type Foo<T> = T extends `*${infer S}*` ? S : never;

type TF1 = Foo<any>; // never
type TF2 = Foo<string>; // never
type TF3 = Foo<'abc'>; // never
type TF4 = Foo<'*abc*'>; // 'abc'

// Cross product unions limited to 100,000 constituents

type A = any;
Expand Down
14 changes: 14 additions & 0 deletions tests/baselines/reference/templateLiteralTypes1.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@ type Chars<S extends string> =

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

// Infer never when source isn't a literal type that matches the pattern

type Foo<T> = T extends `*${infer S}*` ? S : never;

type TF1 = Foo<any>; // never
type TF2 = Foo<string>; // never
type TF3 = Foo<'abc'>; // never
type TF4 = Foo<'*abc*'>; // 'abc'

// Cross product unions limited to 100,000 constituents

type A = any;
Expand Down Expand Up @@ -329,6 +338,11 @@ declare type S2<S extends string> = S;
declare type TV1 = `${infer X}`;
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;
declare type L1 = Chars<'FooBarBazThisIsALongerString'>;
declare type Foo<T> = T extends `*${infer S}*` ? S : never;
declare type TF1 = Foo<any>;
declare type TF2 = Foo<string>;
declare type TF3 = Foo<'abc'>;
declare type TF4 = Foo<'*abc*'>;
declare type A = any;
declare type U1 = {
a1: A;
Expand Down
Loading