Skip to content

Commit c506148

Browse files
authored
Retain substitution types through instantiation if possible (#30059)
1 parent 0e858a6 commit c506148

File tree

5 files changed

+200
-1
lines changed

5 files changed

+200
-1
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11062,7 +11062,13 @@ namespace ts {
1106211062
return getConditionalTypeInstantiation(<ConditionalType>type, combineTypeMappers((<ConditionalType>type).mapper, mapper));
1106311063
}
1106411064
if (flags & TypeFlags.Substitution) {
11065-
return instantiateType((<SubstitutionType>type).typeVariable, mapper);
11065+
const maybeVariable = instantiateType((<SubstitutionType>type).typeVariable, mapper);
11066+
if (maybeVariable.flags & TypeFlags.TypeVariable) {
11067+
return getSubstitutionType(maybeVariable as TypeVariable, instantiateType((<SubstitutionType>type).substitute, mapper));
11068+
}
11069+
else {
11070+
return maybeVariable;
11071+
}
1106611072
}
1106711073
return type;
1106811074
}
@@ -14465,6 +14471,9 @@ namespace ts {
1446514471
}
1446614472
}
1446714473
}
14474+
else if (target.flags & TypeFlags.Substitution) {
14475+
inferFromTypes(source, (target as SubstitutionType).typeVariable);
14476+
}
1446814477
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
1446914478
// If source and target are references to the same generic type, infer from type arguments
1447014479
const sourceTypes = (<TypeReference>source).typeArguments || emptyArray;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [inlinedAliasAssignableToConstraintSameAsAlias.ts]
2+
interface RelationFields {
3+
x: A;
4+
y: A[];
5+
z: A[];
6+
}
7+
type Name = keyof RelationFields;
8+
type ShouldA<RF extends RelationFields, N extends Name> = RF[N] extends A[]
9+
? RF[N][0]
10+
: never;
11+
12+
class A {
13+
x: A;
14+
y: A[];
15+
z: A[];
16+
17+
whereRelated< // Works // Type is same as A1, but is not assignable to type A
18+
RF extends RelationFields = RelationFields,
19+
N extends Name = Name,
20+
A1 extends A = RF[N] extends A[] ? RF[N][0] : never,
21+
A2 extends A = ShouldA<RF, N>
22+
>(): number {
23+
return 1;
24+
}
25+
}
26+
27+
28+
//// [inlinedAliasAssignableToConstraintSameAsAlias.js]
29+
var A = /** @class */ (function () {
30+
function A() {
31+
}
32+
A.prototype.whereRelated = function () {
33+
return 1;
34+
};
35+
return A;
36+
}());
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
=== tests/cases/compiler/inlinedAliasAssignableToConstraintSameAsAlias.ts ===
2+
interface RelationFields {
3+
>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0))
4+
5+
x: A;
6+
>x : Symbol(RelationFields.x, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 26))
7+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
8+
9+
y: A[];
10+
>y : Symbol(RelationFields.y, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 1, 7))
11+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
12+
13+
z: A[];
14+
>z : Symbol(RelationFields.z, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 2, 9))
15+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
16+
}
17+
type Name = keyof RelationFields;
18+
>Name : Symbol(Name, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 4, 1))
19+
>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0))
20+
21+
type ShouldA<RF extends RelationFields, N extends Name> = RF[N] extends A[]
22+
>ShouldA : Symbol(ShouldA, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 5, 33))
23+
>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 13))
24+
>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0))
25+
>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 39))
26+
>Name : Symbol(Name, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 4, 1))
27+
>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 13))
28+
>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 39))
29+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
30+
31+
? RF[N][0]
32+
>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 13))
33+
>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 39))
34+
35+
: never;
36+
37+
class A {
38+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
39+
40+
x: A;
41+
>x : Symbol(A.x, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 10, 9))
42+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
43+
44+
y: A[];
45+
>y : Symbol(A.y, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 11, 7))
46+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
47+
48+
z: A[];
49+
>z : Symbol(A.z, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 12, 9))
50+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
51+
52+
whereRelated< // Works // Type is same as A1, but is not assignable to type A
53+
>whereRelated : Symbol(A.whereRelated, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 13, 9))
54+
55+
RF extends RelationFields = RelationFields,
56+
>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 15, 15))
57+
>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0))
58+
>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0))
59+
60+
N extends Name = Name,
61+
>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 16, 47))
62+
>Name : Symbol(Name, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 4, 1))
63+
>Name : Symbol(Name, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 4, 1))
64+
65+
A1 extends A = RF[N] extends A[] ? RF[N][0] : never,
66+
>A1 : Symbol(A1, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 17, 26))
67+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
68+
>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 15, 15))
69+
>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 16, 47))
70+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
71+
>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 15, 15))
72+
>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 16, 47))
73+
74+
A2 extends A = ShouldA<RF, N>
75+
>A2 : Symbol(A2, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 18, 56))
76+
>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10))
77+
>ShouldA : Symbol(ShouldA, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 5, 33))
78+
>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 15, 15))
79+
>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 16, 47))
80+
81+
>(): number {
82+
return 1;
83+
}
84+
}
85+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/inlinedAliasAssignableToConstraintSameAsAlias.ts ===
2+
interface RelationFields {
3+
x: A;
4+
>x : A
5+
6+
y: A[];
7+
>y : A[]
8+
9+
z: A[];
10+
>z : A[]
11+
}
12+
type Name = keyof RelationFields;
13+
>Name : "x" | "y" | "z"
14+
15+
type ShouldA<RF extends RelationFields, N extends Name> = RF[N] extends A[]
16+
>ShouldA : ShouldA<RF, N>
17+
18+
? RF[N][0]
19+
: never;
20+
21+
class A {
22+
>A : A
23+
24+
x: A;
25+
>x : A
26+
27+
y: A[];
28+
>y : A[]
29+
30+
z: A[];
31+
>z : A[]
32+
33+
whereRelated< // Works // Type is same as A1, but is not assignable to type A
34+
>whereRelated : <RF extends RelationFields = RelationFields, N extends "x" | "y" | "z" = "x" | "y" | "z", A1 extends A = RF[N] extends A[] ? RF[N][0] : never, A2 extends A = ShouldA<RF, N>>() => number
35+
36+
RF extends RelationFields = RelationFields,
37+
N extends Name = Name,
38+
A1 extends A = RF[N] extends A[] ? RF[N][0] : never,
39+
A2 extends A = ShouldA<RF, N>
40+
>(): number {
41+
return 1;
42+
>1 : 1
43+
}
44+
}
45+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
interface RelationFields {
2+
x: A;
3+
y: A[];
4+
z: A[];
5+
}
6+
type Name = keyof RelationFields;
7+
type ShouldA<RF extends RelationFields, N extends Name> = RF[N] extends A[]
8+
? RF[N][0]
9+
: never;
10+
11+
class A {
12+
x: A;
13+
y: A[];
14+
z: A[];
15+
16+
whereRelated< // Works // Type is same as A1, but is not assignable to type A
17+
RF extends RelationFields = RelationFields,
18+
N extends Name = Name,
19+
A1 extends A = RF[N] extends A[] ? RF[N][0] : never,
20+
A2 extends A = ShouldA<RF, N>
21+
>(): number {
22+
return 1;
23+
}
24+
}

0 commit comments

Comments
 (0)