Skip to content

Commit f078ab0

Browse files
authored
Avoid rewriting homomorphic mapped types with homomorphic instantiations (#53215)
1 parent e9836a4 commit f078ab0

6 files changed

+89
-3
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6633,9 +6633,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
66336633
return typeToTypeNodeHelper(type, context);
66346634
}
66356635

6636+
function isMappedTypeHomomorphic(type: MappedType) {
6637+
return !!getHomomorphicTypeVariable(type);
6638+
}
6639+
66366640
function isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type: MappedType) {
6637-
return isMappedTypeWithKeyofConstraintDeclaration(type)
6638-
&& !(getModifiersTypeFromMappedType(type).flags & TypeFlags.TypeParameter);
6641+
return !!type.target && isMappedTypeHomomorphic(type.target as MappedType) && !isMappedTypeHomomorphic(type);
66396642
}
66406643

66416644
function createMappedTypeNodeFromType(type: MappedType) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [mappedTypeGenericInstantiationPreservesInlineForm.ts]
2+
// repro from #53109
3+
4+
export const test1 = <T = Record<string, never>>(schema: {
5+
[K in keyof Required<T>]: T[K];
6+
}) => {}
7+
8+
export function test2<T = Record<string, never>>(schema: {
9+
[K in keyof Required<T>]: T[K];
10+
}) {};
11+
12+
13+
14+
15+
//// [mappedTypeGenericInstantiationPreservesInlineForm.d.ts]
16+
export declare const test1: <T = Record<string, never>>(schema: { [K in keyof Required<T>]: T[K]; }) => void;
17+
export declare function test2<T = Record<string, never>>(schema: {
18+
[K in keyof Required<T>]: T[K];
19+
}): void;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/mappedTypeGenericInstantiationPreservesInlineForm.ts ===
2+
// repro from #53109
3+
4+
export const test1 = <T = Record<string, never>>(schema: {
5+
>test1 : Symbol(test1, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 12))
6+
>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 22))
7+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
8+
>schema : Symbol(schema, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 49))
9+
10+
[K in keyof Required<T>]: T[K];
11+
>K : Symbol(K, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 3, 5))
12+
>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --))
13+
>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 22))
14+
>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 22))
15+
>K : Symbol(K, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 3, 5))
16+
17+
}) => {}
18+
19+
export function test2<T = Record<string, never>>(schema: {
20+
>test2 : Symbol(test2, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 4, 8))
21+
>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 6, 22))
22+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
23+
>schema : Symbol(schema, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 6, 49))
24+
25+
[K in keyof Required<T>]: T[K];
26+
>K : Symbol(K, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 7, 5))
27+
>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --))
28+
>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 6, 22))
29+
>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 6, 22))
30+
>K : Symbol(K, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 7, 5))
31+
32+
}) {};
33+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/compiler/mappedTypeGenericInstantiationPreservesInlineForm.ts ===
2+
// repro from #53109
3+
4+
export const test1 = <T = Record<string, never>>(schema: {
5+
>test1 : <T = Record<string, never>>(schema: { [K in keyof Required<T>]: T[K]; }) => void
6+
><T = Record<string, never>>(schema: { [K in keyof Required<T>]: T[K];}) => {} : <T = Record<string, never>>(schema: { [K in keyof Required<T>]: T[K]; }) => void
7+
>schema : { [K in keyof Required<T>]: T[K]; }
8+
9+
[K in keyof Required<T>]: T[K];
10+
}) => {}
11+
12+
export function test2<T = Record<string, never>>(schema: {
13+
>test2 : <T = Record<string, never>>(schema: { [K in keyof Required<T>]: T[K]; }) => void
14+
>schema : { [K in keyof Required<T>]: T[K]; }
15+
16+
[K in keyof Required<T>]: T[K];
17+
}) {};
18+

tests/baselines/reference/mappedTypeUnionConstraintInferences.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export declare type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
3838
export declare type PartialProperties<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>;
3939
export declare function doSomething_Actual<T extends {
4040
prop: string;
41-
}>(a: T): PartialProperties<T, "prop"> extends infer T_1 ? { [P in keyof T_1]: PartialProperties<T, "prop">[P]; } : never;
41+
}>(a: T): { [P in keyof PartialProperties<T, "prop">]: PartialProperties<T, "prop">[P]; };
4242
export declare function doSomething_Expected<T extends {
4343
prop: string;
4444
}>(a: T): {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @strict: true
2+
// @declaration: true
3+
// @emitDeclarationOnly: true
4+
5+
// repro from #53109
6+
7+
export const test1 = <T = Record<string, never>>(schema: {
8+
[K in keyof Required<T>]: T[K];
9+
}) => {}
10+
11+
export function test2<T = Record<string, never>>(schema: {
12+
[K in keyof Required<T>]: T[K];
13+
}) {};

0 commit comments

Comments
 (0)