Skip to content

Commit 55d4c3d

Browse files
committed
Add inference priority for template type placeholders
1 parent c8da16a commit 55d4c3d

File tree

9 files changed

+145
-37
lines changed

9 files changed

+145
-37
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22771,9 +22771,12 @@ namespace ts {
2277122771
}
2277222772

2277322773
if (sourceTypes) {
22774+
const savedPriority = priority;
22775+
priority |= InferencePriority.TemplateLiteralPlaceholder;
2277422776
for (const source of sourceTypes) {
2277522777
inferFromTypes(source, target);
2277622778
}
22779+
priority = savedPriority;
2277722780
}
2277822781
else {
2277922782
inferFromTypes(source, target);

src/compiler/types.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5858,19 +5858,20 @@ namespace ts {
58585858

58595859
export const enum InferencePriority {
58605860
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
5861-
SpeculativeTuple = 1 << 1, // Speculative tuple inference
5862-
SubstituteSource = 1 << 2, // Source of inference originated within a substitution type's substitute
5863-
HomomorphicMappedType = 1 << 3, // Reverse inference for homomorphic mapped type
5864-
PartialHomomorphicMappedType = 1 << 4, // Partial reverse inference for homomorphic mapped type
5865-
MappedTypeConstraint = 1 << 5, // Reverse inference for mapped type
5866-
ContravariantConditional = 1 << 6, // Conditional type in contravariant position
5867-
ReturnType = 1 << 7, // Inference made from return type of generic function
5868-
LiteralKeyof = 1 << 8, // Inference made from a string literal to a keyof T
5869-
NoConstraints = 1 << 9, // Don't infer from constraints of instantiable types
5870-
AlwaysStrict = 1 << 10, // Always use strict rules for contravariant inferences
5871-
MaxValue = 1 << 11, // Seed for inference priority tracking
5872-
5873-
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
5861+
TemplateLiteralPlaceholder = 1 << 1, // Inference to a template literal type placeholder
5862+
SpeculativeTuple = 1 << 2, // Speculative tuple inference
5863+
SubstituteSource = 1 << 3, // Source of inference originated within a substitution type's substitute
5864+
HomomorphicMappedType = 1 << 4, // Reverse inference for homomorphic mapped type
5865+
PartialHomomorphicMappedType = 1 << 5, // Partial reverse inference for homomorphic mapped type
5866+
MappedTypeConstraint = 1 << 6, // Reverse inference for mapped type
5867+
ContravariantConditional = 1 << 7, // Conditional type in contravariant position
5868+
ReturnType = 1 << 8, // Inference made from return type of generic function
5869+
LiteralKeyof = 1 << 9, // Inference made from a string literal to a keyof T
5870+
NoConstraints = 1 << 10, // Don't infer from constraints of instantiable types
5871+
AlwaysStrict = 1 << 11, // Always use strict rules for contravariant inferences
5872+
MaxValue = 1 << 12, // Seed for inference priority tracking
5873+
5874+
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof | TemplateLiteralPlaceholder, // These priorities imply that the resulting type should be a combination of all candidates
58745875
Circularity = -1, // Inference circularity (value less than all other priorities)
58755876
}
58765877

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,18 +2823,19 @@ declare namespace ts {
28232823
}
28242824
export enum InferencePriority {
28252825
NakedTypeVariable = 1,
2826-
SpeculativeTuple = 2,
2827-
SubstituteSource = 4,
2828-
HomomorphicMappedType = 8,
2829-
PartialHomomorphicMappedType = 16,
2830-
MappedTypeConstraint = 32,
2831-
ContravariantConditional = 64,
2832-
ReturnType = 128,
2833-
LiteralKeyof = 256,
2834-
NoConstraints = 512,
2835-
AlwaysStrict = 1024,
2836-
MaxValue = 2048,
2837-
PriorityImpliesCombination = 416,
2826+
TemplateLiteralPlaceholder = 2,
2827+
SpeculativeTuple = 4,
2828+
SubstituteSource = 8,
2829+
HomomorphicMappedType = 16,
2830+
PartialHomomorphicMappedType = 32,
2831+
MappedTypeConstraint = 64,
2832+
ContravariantConditional = 128,
2833+
ReturnType = 256,
2834+
LiteralKeyof = 512,
2835+
NoConstraints = 1024,
2836+
AlwaysStrict = 2048,
2837+
MaxValue = 4096,
2838+
PriorityImpliesCombination = 834,
28382839
Circularity = -1
28392840
}
28402841
/** @deprecated Use FileExtensionInfo instead. */

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,18 +2823,19 @@ declare namespace ts {
28232823
}
28242824
export enum InferencePriority {
28252825
NakedTypeVariable = 1,
2826-
SpeculativeTuple = 2,
2827-
SubstituteSource = 4,
2828-
HomomorphicMappedType = 8,
2829-
PartialHomomorphicMappedType = 16,
2830-
MappedTypeConstraint = 32,
2831-
ContravariantConditional = 64,
2832-
ReturnType = 128,
2833-
LiteralKeyof = 256,
2834-
NoConstraints = 512,
2835-
AlwaysStrict = 1024,
2836-
MaxValue = 2048,
2837-
PriorityImpliesCombination = 416,
2826+
TemplateLiteralPlaceholder = 2,
2827+
SpeculativeTuple = 4,
2828+
SubstituteSource = 8,
2829+
HomomorphicMappedType = 16,
2830+
PartialHomomorphicMappedType = 32,
2831+
MappedTypeConstraint = 64,
2832+
ContravariantConditional = 128,
2833+
ReturnType = 256,
2834+
LiteralKeyof = 512,
2835+
NoConstraints = 1024,
2836+
AlwaysStrict = 2048,
2837+
MaxValue = 4096,
2838+
PriorityImpliesCombination = 834,
28382839
Circularity = -1
28392840
}
28402841
/** @deprecated Use FileExtensionInfo instead. */

tests/baselines/reference/templateLiteralTypes4.errors.txt

Lines changed: 10 additions & 0 deletions
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

Lines changed: 17 additions & 0 deletions
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

Lines changed: 33 additions & 0 deletions
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

Lines changed: 32 additions & 0 deletions
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

Lines changed: 10 additions & 0 deletions
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)