Skip to content

Commit 9f33bf1

Browse files
TypeScript Botahejlsberg
andauthored
🤖 Pick PR #58098 (Fix constraints of nested homomorph...) into release-5.4 (#58118)
Co-authored-by: Anders Hejlsberg <andersh@microsoft.com>
1 parent 71b2f84 commit 9f33bf1

File tree

4 files changed

+103
-7
lines changed

4 files changed

+103
-7
lines changed

‎src/compiler/checker.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14552,16 +14552,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1455214552
return type.resolvedApparentType || (type.resolvedApparentType = getResolvedApparentTypeOfMappedType(type));
1455314553
}
1455414554

14555-
function getResolvedApparentTypeOfMappedType(type: MappedType) {
14555+
function getResolvedApparentTypeOfMappedType(type: MappedType): Type {
1455614556
const target = (type.target ?? type) as MappedType;
1455714557
const typeVariable = getHomomorphicTypeVariable(target);
1455814558
if (typeVariable && !target.declaration.nameType) {
14559-
const constraint = getConstraintTypeFromMappedType(type);
14560-
if (constraint.flags & TypeFlags.Index) {
14561-
const baseConstraint = getBaseConstraintOfType((constraint as IndexType).type);
14562-
if (baseConstraint && everyType(baseConstraint, t => isArrayOrTupleType(t) || isArrayOrTupleOrIntersection(t))) {
14563-
return instantiateType(target, prependTypeMapping(typeVariable, baseConstraint, type.mapper));
14564-
}
14559+
// We have a homomorphic mapped type or an instantiation of a homomorphic mapped type, i.e. a type
14560+
// of the form { [P in keyof T]: X }. Obtain the modifiers type (the T of the keyof T), and if it is
14561+
// another generic mapped type, recursively obtain its apparent type. Otherwise, obtain its base
14562+
// constraint. Then, if every constituent of the base constraint is an array or tuple type, apply
14563+
// this mapped type to the base constraint. It is safe to recurse when the modifiers type is a
14564+
// mapped type because we protect again circular constraints in getTypeFromMappedTypeNode.
14565+
const modifiersType = getModifiersTypeFromMappedType(type);
14566+
const baseConstraint = isGenericMappedType(modifiersType) ? getApparentTypeOfMappedType(modifiersType) : getBaseConstraintOfType(modifiersType);
14567+
if (baseConstraint && everyType(baseConstraint, t => isArrayOrTupleType(t) || isArrayOrTupleOrIntersection(t))) {
14568+
return instantiateType(target, prependTypeMapping(typeVariable, baseConstraint, type.mapper));
1456514569
}
1456614570
}
1456714571
return type;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//// [tests/cases/compiler/homomorphicMappedTypeNesting.ts] ////
2+
3+
=== homomorphicMappedTypeNesting.ts ===
4+
// Repro from #58060
5+
6+
type Box<T extends string> = { v: T };
7+
>Box : Symbol(Box, Decl(homomorphicMappedTypeNesting.ts, 0, 0))
8+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 2, 9))
9+
>v : Symbol(v, Decl(homomorphicMappedTypeNesting.ts, 2, 30))
10+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 2, 9))
11+
12+
type Test<T extends string[]> = T
13+
>Test : Symbol(Test, Decl(homomorphicMappedTypeNesting.ts, 2, 38))
14+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 4, 10))
15+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 4, 10))
16+
17+
type UnboxArray<T> = {
18+
>UnboxArray : Symbol(UnboxArray, Decl(homomorphicMappedTypeNesting.ts, 4, 33))
19+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 6, 16))
20+
21+
[K in keyof T]: T[K] extends Box<infer R> ? R : never;
22+
>K : Symbol(K, Decl(homomorphicMappedTypeNesting.ts, 7, 5))
23+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 6, 16))
24+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 6, 16))
25+
>K : Symbol(K, Decl(homomorphicMappedTypeNesting.ts, 7, 5))
26+
>Box : Symbol(Box, Decl(homomorphicMappedTypeNesting.ts, 0, 0))
27+
>R : Symbol(R, Decl(homomorphicMappedTypeNesting.ts, 7, 42))
28+
>R : Symbol(R, Decl(homomorphicMappedTypeNesting.ts, 7, 42))
29+
30+
};
31+
32+
type Identity<T> = { [K in keyof T]: T[K] };
33+
>Identity : Symbol(Identity, Decl(homomorphicMappedTypeNesting.ts, 8, 2))
34+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 10, 14))
35+
>K : Symbol(K, Decl(homomorphicMappedTypeNesting.ts, 10, 22))
36+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 10, 14))
37+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 10, 14))
38+
>K : Symbol(K, Decl(homomorphicMappedTypeNesting.ts, 10, 22))
39+
40+
declare function fnBad<T extends Array<Box<string>>>(...args: T): Test<Identity<UnboxArray<T>>>;
41+
>fnBad : Symbol(fnBad, Decl(homomorphicMappedTypeNesting.ts, 10, 44))
42+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 12, 23))
43+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
44+
>Box : Symbol(Box, Decl(homomorphicMappedTypeNesting.ts, 0, 0))
45+
>args : Symbol(args, Decl(homomorphicMappedTypeNesting.ts, 12, 53))
46+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 12, 23))
47+
>Test : Symbol(Test, Decl(homomorphicMappedTypeNesting.ts, 2, 38))
48+
>Identity : Symbol(Identity, Decl(homomorphicMappedTypeNesting.ts, 8, 2))
49+
>UnboxArray : Symbol(UnboxArray, Decl(homomorphicMappedTypeNesting.ts, 4, 33))
50+
>T : Symbol(T, Decl(homomorphicMappedTypeNesting.ts, 12, 23))
51+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [tests/cases/compiler/homomorphicMappedTypeNesting.ts] ////
2+
3+
=== homomorphicMappedTypeNesting.ts ===
4+
// Repro from #58060
5+
6+
type Box<T extends string> = { v: T };
7+
>Box : Box<T>
8+
>v : T
9+
10+
type Test<T extends string[]> = T
11+
>Test : T
12+
13+
type UnboxArray<T> = {
14+
>UnboxArray : UnboxArray<T>
15+
16+
[K in keyof T]: T[K] extends Box<infer R> ? R : never;
17+
};
18+
19+
type Identity<T> = { [K in keyof T]: T[K] };
20+
>Identity : Identity<T>
21+
22+
declare function fnBad<T extends Array<Box<string>>>(...args: T): Test<Identity<UnboxArray<T>>>;
23+
>fnBad : <T extends Box<string>[]>(...args: T) => Test<Identity<UnboxArray<T>>>
24+
>args : T
25+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// Repro from #58060
5+
6+
type Box<T extends string> = { v: T };
7+
8+
type Test<T extends string[]> = T
9+
10+
type UnboxArray<T> = {
11+
[K in keyof T]: T[K] extends Box<infer R> ? R : never;
12+
};
13+
14+
type Identity<T> = { [K in keyof T]: T[K] };
15+
16+
declare function fnBad<T extends Array<Box<string>>>(...args: T): Test<Identity<UnboxArray<T>>>;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy