Skip to content

Commit 408c804

Browse files
authored
Properly instantiate inferred constraints in conditional types (#42747)
* fix combined type mapper in getConditionalType * Add regression tests
1 parent f0a72e2 commit 408c804

File tree

5 files changed

+123
-1
lines changed

5 files changed

+123
-1
lines changed

src/compiler/checker.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -14796,7 +14796,10 @@ namespace ts {
1479614796
// types rules (i.e. proper contravariance) for inferences.
1479714797
inferTypes(context.inferences, checkType, extendsType, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict);
1479814798
}
14799-
combinedMapper = mergeTypeMappers(mapper, context.mapper);
14799+
// It's possible for 'infer T' type paramteters to be given uninstantiated constraints when the
14800+
// those type parameters are used in type references (see getInferredTypeParameterConstraint). For
14801+
// that reason we need context.mapper to be first in the combined mapper. See #42636 for examples.
14802+
combinedMapper = mapper ? combineTypeMappers(context.mapper, mapper) : context.mapper;
1480014803
}
1480114804
// Instantiate the extends type including inferences for 'infer T' type parameters
1480214805
const inferredExtendsType = combinedMapper ? instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), combinedMapper) : extendsType;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [inferTypeParameterConstraints.ts]
2+
// Repro from #42636
3+
4+
type SubGuard<A, X extends [A]> = X;
5+
6+
type IsSub<M extends any[], S extends any[]> = M extends [...SubGuard<M[number], infer B>, ...S, ...any[]] ? B : never;
7+
8+
type E0 = IsSub<[1, 2, 3, 4], [2, 3, 4]>; // [1 | 2 | 3 | 4]
9+
10+
type E1 = [1, 2, 3, 4] extends [...infer B, 2, 3, 4, ...any[]] ? B : never; // unknown[]
11+
12+
// Repro from #42636
13+
14+
type Constrain<T extends C, C> = unknown;
15+
16+
type Foo<A> = A extends Constrain<infer X, A> ? X : never;
17+
18+
type T0 = Foo<string>; // string
19+
20+
21+
//// [inferTypeParameterConstraints.js]
22+
"use strict";
23+
// Repro from #42636
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
=== tests/cases/compiler/inferTypeParameterConstraints.ts ===
2+
// Repro from #42636
3+
4+
type SubGuard<A, X extends [A]> = X;
5+
>SubGuard : Symbol(SubGuard, Decl(inferTypeParameterConstraints.ts, 0, 0))
6+
>A : Symbol(A, Decl(inferTypeParameterConstraints.ts, 2, 14))
7+
>X : Symbol(X, Decl(inferTypeParameterConstraints.ts, 2, 16))
8+
>A : Symbol(A, Decl(inferTypeParameterConstraints.ts, 2, 14))
9+
>X : Symbol(X, Decl(inferTypeParameterConstraints.ts, 2, 16))
10+
11+
type IsSub<M extends any[], S extends any[]> = M extends [...SubGuard<M[number], infer B>, ...S, ...any[]] ? B : never;
12+
>IsSub : Symbol(IsSub, Decl(inferTypeParameterConstraints.ts, 2, 36))
13+
>M : Symbol(M, Decl(inferTypeParameterConstraints.ts, 4, 11))
14+
>S : Symbol(S, Decl(inferTypeParameterConstraints.ts, 4, 27))
15+
>M : Symbol(M, Decl(inferTypeParameterConstraints.ts, 4, 11))
16+
>SubGuard : Symbol(SubGuard, Decl(inferTypeParameterConstraints.ts, 0, 0))
17+
>M : Symbol(M, Decl(inferTypeParameterConstraints.ts, 4, 11))
18+
>B : Symbol(B, Decl(inferTypeParameterConstraints.ts, 4, 86))
19+
>S : Symbol(S, Decl(inferTypeParameterConstraints.ts, 4, 27))
20+
>B : Symbol(B, Decl(inferTypeParameterConstraints.ts, 4, 86))
21+
22+
type E0 = IsSub<[1, 2, 3, 4], [2, 3, 4]>; // [1 | 2 | 3 | 4]
23+
>E0 : Symbol(E0, Decl(inferTypeParameterConstraints.ts, 4, 119))
24+
>IsSub : Symbol(IsSub, Decl(inferTypeParameterConstraints.ts, 2, 36))
25+
26+
type E1 = [1, 2, 3, 4] extends [...infer B, 2, 3, 4, ...any[]] ? B : never; // unknown[]
27+
>E1 : Symbol(E1, Decl(inferTypeParameterConstraints.ts, 6, 41))
28+
>B : Symbol(B, Decl(inferTypeParameterConstraints.ts, 8, 40))
29+
>B : Symbol(B, Decl(inferTypeParameterConstraints.ts, 8, 40))
30+
31+
// Repro from #42636
32+
33+
type Constrain<T extends C, C> = unknown;
34+
>Constrain : Symbol(Constrain, Decl(inferTypeParameterConstraints.ts, 8, 75))
35+
>T : Symbol(T, Decl(inferTypeParameterConstraints.ts, 12, 15))
36+
>C : Symbol(C, Decl(inferTypeParameterConstraints.ts, 12, 27))
37+
>C : Symbol(C, Decl(inferTypeParameterConstraints.ts, 12, 27))
38+
39+
type Foo<A> = A extends Constrain<infer X, A> ? X : never;
40+
>Foo : Symbol(Foo, Decl(inferTypeParameterConstraints.ts, 12, 41))
41+
>A : Symbol(A, Decl(inferTypeParameterConstraints.ts, 14, 9))
42+
>A : Symbol(A, Decl(inferTypeParameterConstraints.ts, 14, 9))
43+
>Constrain : Symbol(Constrain, Decl(inferTypeParameterConstraints.ts, 8, 75))
44+
>X : Symbol(X, Decl(inferTypeParameterConstraints.ts, 14, 39))
45+
>A : Symbol(A, Decl(inferTypeParameterConstraints.ts, 14, 9))
46+
>X : Symbol(X, Decl(inferTypeParameterConstraints.ts, 14, 39))
47+
48+
type T0 = Foo<string>; // string
49+
>T0 : Symbol(T0, Decl(inferTypeParameterConstraints.ts, 14, 58))
50+
>Foo : Symbol(Foo, Decl(inferTypeParameterConstraints.ts, 12, 41))
51+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/inferTypeParameterConstraints.ts ===
2+
// Repro from #42636
3+
4+
type SubGuard<A, X extends [A]> = X;
5+
>SubGuard : X
6+
7+
type IsSub<M extends any[], S extends any[]> = M extends [...SubGuard<M[number], infer B>, ...S, ...any[]] ? B : never;
8+
>IsSub : IsSub<M, S>
9+
10+
type E0 = IsSub<[1, 2, 3, 4], [2, 3, 4]>; // [1 | 2 | 3 | 4]
11+
>E0 : [1 | 4 | 2 | 3]
12+
13+
type E1 = [1, 2, 3, 4] extends [...infer B, 2, 3, 4, ...any[]] ? B : never; // unknown[]
14+
>E1 : unknown[]
15+
16+
// Repro from #42636
17+
18+
type Constrain<T extends C, C> = unknown;
19+
>Constrain : unknown
20+
21+
type Foo<A> = A extends Constrain<infer X, A> ? X : never;
22+
>Foo : Foo<A>
23+
24+
type T0 = Foo<string>; // string
25+
>T0 : string
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @strict: true
2+
3+
// Repro from #42636
4+
5+
type SubGuard<A, X extends [A]> = X;
6+
7+
type IsSub<M extends any[], S extends any[]> = M extends [...SubGuard<M[number], infer B>, ...S, ...any[]] ? B : never;
8+
9+
type E0 = IsSub<[1, 2, 3, 4], [2, 3, 4]>; // [1 | 2 | 3 | 4]
10+
11+
type E1 = [1, 2, 3, 4] extends [...infer B, 2, 3, 4, ...any[]] ? B : never; // unknown[]
12+
13+
// Repro from #42636
14+
15+
type Constrain<T extends C, C> = unknown;
16+
17+
type Foo<A> = A extends Constrain<infer X, A> ? X : never;
18+
19+
type T0 = Foo<string>; // string

0 commit comments

Comments
 (0)