Skip to content

Commit df23e95

Browse files
committed
Add inference priority for template type placeholders
1 parent 1bc376f commit df23e95

File tree

9 files changed

+145
-37
lines changed

9 files changed

+145
-37
lines changed

src/compiler/checker.ts

+3
Original file line numberDiff line numberDiff line change
@@ -22424,9 +22424,12 @@ namespace ts {
2242422424
}
2242522425

2242622426
if (sourceTypes) {
22427+
const savedPriority = priority;
22428+
priority |= InferencePriority.TemplateLiteralPlaceholder;
2242722429
for (const source of sourceTypes) {
2242822430
inferFromTypes(source, target);
2242922431
}
22432+
priority = savedPriority;
2243022433
}
2243122434
else {
2243222435
inferFromTypes(source, target);

src/compiler/types.ts

+14-13
Original file line numberDiff line numberDiff line change
@@ -5825,19 +5825,20 @@ namespace ts {
58255825

58265826
export const enum InferencePriority {
58275827
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
5828-
SpeculativeTuple = 1 << 1, // Speculative tuple inference
5829-
SubstituteSource = 1 << 2, // Source of inference originated within a substitution type's substitute
5830-
HomomorphicMappedType = 1 << 3, // Reverse inference for homomorphic mapped type
5831-
PartialHomomorphicMappedType = 1 << 4, // Partial reverse inference for homomorphic mapped type
5832-
MappedTypeConstraint = 1 << 5, // Reverse inference for mapped type
5833-
ContravariantConditional = 1 << 6, // Conditional type in contravariant position
5834-
ReturnType = 1 << 7, // Inference made from return type of generic function
5835-
LiteralKeyof = 1 << 8, // Inference made from a string literal to a keyof T
5836-
NoConstraints = 1 << 9, // Don't infer from constraints of instantiable types
5837-
AlwaysStrict = 1 << 10, // Always use strict rules for contravariant inferences
5838-
MaxValue = 1 << 11, // Seed for inference priority tracking
5839-
5840-
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
5828+
TemplateLiteralPlaceholder = 1 << 1, // Inference to a template literal type placeholder
5829+
SpeculativeTuple = 1 << 2, // Speculative tuple inference
5830+
SubstituteSource = 1 << 3, // Source of inference originated within a substitution type's substitute
5831+
HomomorphicMappedType = 1 << 4, // Reverse inference for homomorphic mapped type
5832+
PartialHomomorphicMappedType = 1 << 5, // Partial reverse inference for homomorphic mapped type
5833+
MappedTypeConstraint = 1 << 6, // Reverse inference for mapped type
5834+
ContravariantConditional = 1 << 7, // Conditional type in contravariant position
5835+
ReturnType = 1 << 8, // Inference made from return type of generic function
5836+
LiteralKeyof = 1 << 9, // Inference made from a string literal to a keyof T
5837+
NoConstraints = 1 << 10, // Don't infer from constraints of instantiable types
5838+
AlwaysStrict = 1 << 11, // Always use strict rules for contravariant inferences
5839+
MaxValue = 1 << 12, // Seed for inference priority tracking
5840+
5841+
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof | TemplateLiteralPlaceholder, // These priorities imply that the resulting type should be a combination of all candidates
58415842
Circularity = -1, // Inference circularity (value less than all other priorities)
58425843
}
58435844

tests/baselines/reference/api/tsserverlibrary.d.ts

+13-12
Original file line numberDiff line numberDiff line change
@@ -2805,18 +2805,19 @@ declare namespace ts {
28052805
}
28062806
export enum InferencePriority {
28072807
NakedTypeVariable = 1,
2808-
SpeculativeTuple = 2,
2809-
SubstituteSource = 4,
2810-
HomomorphicMappedType = 8,
2811-
PartialHomomorphicMappedType = 16,
2812-
MappedTypeConstraint = 32,
2813-
ContravariantConditional = 64,
2814-
ReturnType = 128,
2815-
LiteralKeyof = 256,
2816-
NoConstraints = 512,
2817-
AlwaysStrict = 1024,
2818-
MaxValue = 2048,
2819-
PriorityImpliesCombination = 416,
2808+
TemplateLiteralPlaceholder = 2,
2809+
SpeculativeTuple = 4,
2810+
SubstituteSource = 8,
2811+
HomomorphicMappedType = 16,
2812+
PartialHomomorphicMappedType = 32,
2813+
MappedTypeConstraint = 64,
2814+
ContravariantConditional = 128,
2815+
ReturnType = 256,
2816+
LiteralKeyof = 512,
2817+
NoConstraints = 1024,
2818+
AlwaysStrict = 2048,
2819+
MaxValue = 4096,
2820+
PriorityImpliesCombination = 834,
28202821
Circularity = -1
28212822
}
28222823
/** @deprecated Use FileExtensionInfo instead. */

tests/baselines/reference/api/typescript.d.ts

+13-12
Original file line numberDiff line numberDiff line change
@@ -2805,18 +2805,19 @@ declare namespace ts {
28052805
}
28062806
export enum InferencePriority {
28072807
NakedTypeVariable = 1,
2808-
SpeculativeTuple = 2,
2809-
SubstituteSource = 4,
2810-
HomomorphicMappedType = 8,
2811-
PartialHomomorphicMappedType = 16,
2812-
MappedTypeConstraint = 32,
2813-
ContravariantConditional = 64,
2814-
ReturnType = 128,
2815-
LiteralKeyof = 256,
2816-
NoConstraints = 512,
2817-
AlwaysStrict = 1024,
2818-
MaxValue = 2048,
2819-
PriorityImpliesCombination = 416,
2808+
TemplateLiteralPlaceholder = 2,
2809+
SpeculativeTuple = 4,
2810+
SubstituteSource = 8,
2811+
HomomorphicMappedType = 16,
2812+
PartialHomomorphicMappedType = 32,
2813+
MappedTypeConstraint = 64,
2814+
ContravariantConditional = 128,
2815+
ReturnType = 256,
2816+
LiteralKeyof = 512,
2817+
NoConstraints = 1024,
2818+
AlwaysStrict = 2048,
2819+
MaxValue = 4096,
2820+
PriorityImpliesCombination = 834,
28202821
Circularity = -1
28212822
}
28222823
/** @deprecated Use FileExtensionInfo instead. */

tests/baselines/reference/templateLiteralTypes4.errors.txt

+10
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,14 @@ tests/cases/conformance/types/literal/templateLiteralTypes4.ts(97,12): error TS2
104104
p.setIndex(2, 3); // error, 2 is not a valid index
105105
~
106106
!!! error TS2345: Argument of type '2' is not assignable to parameter of type '0 | 1'.
107+
108+
declare function f1<T extends string | number>(s: `**${T}**`): T;
109+
f1("**123**"); // "123" | 123
110+
111+
declare function f2<T extends string | bigint>(s: `**${T}**`): T;
112+
f2("**123**"); // "123" | 123n
113+
114+
declare function f3<T extends string | boolean>(s: `**${T}**`): T;
115+
f3("**true**"); // true | "true"
116+
f3("**false**"); // false | "false"
107117

tests/baselines/reference/templateLiteralTypes4.js

+17
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@ p.getIndex(2); // error, 2 is not a valid index
9696
p.setIndex(0, 0); // ok, 0 is a valid index
9797
p.setIndex(1, 0); // ok, 1 is a valid index
9898
p.setIndex(2, 3); // error, 2 is not a valid index
99+
100+
declare function f1<T extends string | number>(s: `**${T}**`): T;
101+
f1("**123**"); // "123" | 123
102+
103+
declare function f2<T extends string | bigint>(s: `**${T}**`): T;
104+
f2("**123**"); // "123" | 123n
105+
106+
declare function f3<T extends string | boolean>(s: `**${T}**`): T;
107+
f3("**true**"); // true | "true"
108+
f3("**false**"); // false | "false"
99109

100110

101111
//// [templateLiteralTypes4.js]
@@ -106,6 +116,10 @@ p.getIndex(2); // error, 2 is not a valid index
106116
p.setIndex(0, 0); // ok, 0 is a valid index
107117
p.setIndex(1, 0); // ok, 1 is a valid index
108118
p.setIndex(2, 3); // error, 2 is not a valid index
119+
f1("**123**"); // "123" | 123
120+
f2("**123**"); // "123" | 123n
121+
f3("**true**"); // true | "true"
122+
f3("**false**"); // false | "false"
109123

110124

111125
//// [templateLiteralTypes4.d.ts]
@@ -180,3 +194,6 @@ declare type Point = TypedObject<[
180194
}
181195
]>;
182196
declare const p: Point;
197+
declare function f1<T extends string | number>(s: `**${T}**`): T;
198+
declare function f2<T extends string | bigint>(s: `**${T}**`): T;
199+
declare function f3<T extends string | boolean>(s: `**${T}**`): T;

tests/baselines/reference/templateLiteralTypes4.symbols

+33
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,36 @@ p.setIndex(2, 3); // error, 2 is not a valid index
400400
>p : Symbol(p, Decl(templateLiteralTypes4.ts, 89, 13))
401401
>setIndex : Symbol(TypedObjectMembers.setIndex, Decl(templateLiteralTypes4.ts, 71, 104))
402402

403+
declare function f1<T extends string | number>(s: `**${T}**`): T;
404+
>f1 : Symbol(f1, Decl(templateLiteralTypes4.ts, 96, 17))
405+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 98, 20))
406+
>s : Symbol(s, Decl(templateLiteralTypes4.ts, 98, 47))
407+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 98, 20))
408+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 98, 20))
409+
410+
f1("**123**"); // "123" | 123
411+
>f1 : Symbol(f1, Decl(templateLiteralTypes4.ts, 96, 17))
412+
413+
declare function f2<T extends string | bigint>(s: `**${T}**`): T;
414+
>f2 : Symbol(f2, Decl(templateLiteralTypes4.ts, 99, 14))
415+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 101, 20))
416+
>s : Symbol(s, Decl(templateLiteralTypes4.ts, 101, 47))
417+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 101, 20))
418+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 101, 20))
419+
420+
f2("**123**"); // "123" | 123n
421+
>f2 : Symbol(f2, Decl(templateLiteralTypes4.ts, 99, 14))
422+
423+
declare function f3<T extends string | boolean>(s: `**${T}**`): T;
424+
>f3 : Symbol(f3, Decl(templateLiteralTypes4.ts, 102, 14))
425+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 104, 20))
426+
>s : Symbol(s, Decl(templateLiteralTypes4.ts, 104, 48))
427+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 104, 20))
428+
>T : Symbol(T, Decl(templateLiteralTypes4.ts, 104, 20))
429+
430+
f3("**true**"); // true | "true"
431+
>f3 : Symbol(f3, Decl(templateLiteralTypes4.ts, 102, 14))
432+
433+
f3("**false**"); // false | "false"
434+
>f3 : Symbol(f3, Decl(templateLiteralTypes4.ts, 102, 14))
435+

tests/baselines/reference/templateLiteralTypes4.types

+32
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,35 @@ p.setIndex(2, 3); // error, 2 is not a valid index
242242
>2 : 2
243243
>3 : 3
244244

245+
declare function f1<T extends string | number>(s: `**${T}**`): T;
246+
>f1 : <T extends string | number>(s: `**${T}**`) => T
247+
>s : `**${T}**`
248+
249+
f1("**123**"); // "123" | 123
250+
>f1("**123**") : "123" | 123
251+
>f1 : <T extends string | number>(s: `**${T}**`) => T
252+
>"**123**" : "**123**"
253+
254+
declare function f2<T extends string | bigint>(s: `**${T}**`): T;
255+
>f2 : <T extends string | bigint>(s: `**${T}**`) => T
256+
>s : `**${T}**`
257+
258+
f2("**123**"); // "123" | 123n
259+
>f2("**123**") : "123" | 123n
260+
>f2 : <T extends string | bigint>(s: `**${T}**`) => T
261+
>"**123**" : "**123**"
262+
263+
declare function f3<T extends string | boolean>(s: `**${T}**`): T;
264+
>f3 : <T extends string | boolean>(s: `**${T}**`) => T
265+
>s : `**${T}**`
266+
267+
f3("**true**"); // true | "true"
268+
>f3("**true**") : true | "true"
269+
>f3 : <T extends string | boolean>(s: `**${T}**`) => T
270+
>"**true**" : "**true**"
271+
272+
f3("**false**"); // false | "false"
273+
>f3("**false**") : false | "false"
274+
>f3 : <T extends string | boolean>(s: `**${T}**`) => T
275+
>"**false**" : "**false**"
276+

tests/cases/conformance/types/literal/templateLiteralTypes4.ts

+10
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,13 @@ p.getIndex(2); // error, 2 is not a valid index
9898
p.setIndex(0, 0); // ok, 0 is a valid index
9999
p.setIndex(1, 0); // ok, 1 is a valid index
100100
p.setIndex(2, 3); // error, 2 is not a valid index
101+
102+
declare function f1<T extends string | number>(s: `**${T}**`): T;
103+
f1("**123**"); // "123" | 123
104+
105+
declare function f2<T extends string | bigint>(s: `**${T}**`): T;
106+
f2("**123**"); // "123" | 123n
107+
108+
declare function f3<T extends string | boolean>(s: `**${T}**`): T;
109+
f3("**true**"); // true | "true"
110+
f3("**false**"); // false | "false"

0 commit comments

Comments
 (0)