From a927933be1babb4145f969375863adf0109698b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 12 Mar 2023 10:57:48 +0100 Subject: [PATCH 1/4] Avoid rewriting mapped types that are already inline --- src/compiler/checker.ts | 3 +- ...GenericInstantiationPreservesInlineForm.js | 19 +++++++++++ ...icInstantiationPreservesInlineForm.symbols | 33 +++++++++++++++++++ ...ericInstantiationPreservesInlineForm.types | 18 ++++++++++ .../mappedTypeUnionConstraintInferences.js | 2 +- ...GenericInstantiationPreservesInlineForm.ts | 13 ++++++++ 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.js create mode 100644 tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.symbols create mode 100644 tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.types create mode 100644 tests/cases/compiler/mappedTypeGenericInstantiationPreservesInlineForm.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2515d81a58f7e..1b04c6fbf8a69 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6616,7 +6616,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type: MappedType) { return isMappedTypeWithKeyofConstraintDeclaration(type) - && !(getModifiersTypeFromMappedType(type).flags & TypeFlags.TypeParameter); + && !(getModifiersTypeFromMappedType(type).flags & TypeFlags.TypeParameter) + && !!type.aliasSymbol; } function createMappedTypeNodeFromType(type: MappedType) { diff --git a/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.js b/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.js new file mode 100644 index 0000000000000..3d049a82ae68e --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.js @@ -0,0 +1,19 @@ +//// [mappedTypeGenericInstantiationPreservesInlineForm.ts] +// repro from #53109 + +export const test1 = >(schema: { + [K in keyof Required]: T[K]; +}) => {} + +export function test2>(schema: { + [K in keyof Required]: T[K]; +}) {}; + + + + +//// [mappedTypeGenericInstantiationPreservesInlineForm.d.ts] +export declare const test1: >(schema: { [K in keyof Required]: T[K]; }) => void; +export declare function test2>(schema: { + [K in keyof Required]: T[K]; +}): void; diff --git a/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.symbols b/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.symbols new file mode 100644 index 0000000000000..a550d839ddf4c --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.symbols @@ -0,0 +1,33 @@ +=== tests/cases/compiler/mappedTypeGenericInstantiationPreservesInlineForm.ts === +// repro from #53109 + +export const test1 = >(schema: { +>test1 : Symbol(test1, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 12)) +>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 22)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>schema : Symbol(schema, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 49)) + + [K in keyof Required]: T[K]; +>K : Symbol(K, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 3, 5)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 22)) +>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 2, 22)) +>K : Symbol(K, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 3, 5)) + +}) => {} + +export function test2>(schema: { +>test2 : Symbol(test2, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 4, 8)) +>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 6, 22)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>schema : Symbol(schema, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 6, 49)) + + [K in keyof Required]: T[K]; +>K : Symbol(K, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 7, 5)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 6, 22)) +>T : Symbol(T, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 6, 22)) +>K : Symbol(K, Decl(mappedTypeGenericInstantiationPreservesInlineForm.ts, 7, 5)) + +}) {}; + diff --git a/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.types b/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.types new file mode 100644 index 0000000000000..60581c37ebdce --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.types @@ -0,0 +1,18 @@ +=== tests/cases/compiler/mappedTypeGenericInstantiationPreservesInlineForm.ts === +// repro from #53109 + +export const test1 = >(schema: { +>test1 : >(schema: { [K in keyof Required]: T[K]; }) => void +>>(schema: { [K in keyof Required]: T[K];}) => {} : >(schema: { [K in keyof Required]: T[K]; }) => void +>schema : { [K in keyof Required]: T[K]; } + + [K in keyof Required]: T[K]; +}) => {} + +export function test2>(schema: { +>test2 : >(schema: { [K in keyof Required]: T[K]; }) => void +>schema : { [K in keyof Required]: T[K]; } + + [K in keyof Required]: T[K]; +}) {}; + diff --git a/tests/baselines/reference/mappedTypeUnionConstraintInferences.js b/tests/baselines/reference/mappedTypeUnionConstraintInferences.js index 7d1602718c18b..7d9e714d339bc 100644 --- a/tests/baselines/reference/mappedTypeUnionConstraintInferences.js +++ b/tests/baselines/reference/mappedTypeUnionConstraintInferences.js @@ -38,7 +38,7 @@ export declare type Omit = Pick>; export declare type PartialProperties = Partial> & Omit; export declare function doSomething_Actual(a: T): PartialProperties extends infer T_1 ? { [P in keyof T_1]: PartialProperties[P]; } : never; +}>(a: T): { [P in keyof PartialProperties]: PartialProperties[P]; }; export declare function doSomething_Expected(a: T): { diff --git a/tests/cases/compiler/mappedTypeGenericInstantiationPreservesInlineForm.ts b/tests/cases/compiler/mappedTypeGenericInstantiationPreservesInlineForm.ts new file mode 100644 index 0000000000000..cae88c35591d6 --- /dev/null +++ b/tests/cases/compiler/mappedTypeGenericInstantiationPreservesInlineForm.ts @@ -0,0 +1,13 @@ +// @strict: true +// @declaration: true +// @emitDeclarationOnly: true + +// repro from #53109 + +export const test1 = >(schema: { + [K in keyof Required]: T[K]; +}) => {} + +export function test2>(schema: { + [K in keyof Required]: T[K]; +}) {}; From f562093d9ec731d62f5ded58e024f45c427eeede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 15 Mar 2023 09:54:11 +0100 Subject: [PATCH 2/4] tweak isHomomorphicMappedTypeWithNonHomomorphicInstantiation --- src/compiler/checker.ts | 8 +++++--- .../reference/mappedTypeUnionConstraintInferences.js | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b04c6fbf8a69..42e6f322ea03c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6615,9 +6615,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type: MappedType) { - return isMappedTypeWithKeyofConstraintDeclaration(type) - && !(getModifiersTypeFromMappedType(type).flags & TypeFlags.TypeParameter) - && !!type.aliasSymbol; + if (!isMappedTypeWithKeyofConstraintDeclaration(type)) { + return false; + } + const index = getIndexType(getModifiersTypeFromMappedType(type)); + return !(index.flags & TypeFlags.Index && (index as IndexType).type.flags & TypeFlags.TypeParameter); } function createMappedTypeNodeFromType(type: MappedType) { diff --git a/tests/baselines/reference/mappedTypeUnionConstraintInferences.js b/tests/baselines/reference/mappedTypeUnionConstraintInferences.js index 7d9e714d339bc..7d1602718c18b 100644 --- a/tests/baselines/reference/mappedTypeUnionConstraintInferences.js +++ b/tests/baselines/reference/mappedTypeUnionConstraintInferences.js @@ -38,7 +38,7 @@ export declare type Omit = Pick>; export declare type PartialProperties = Partial> & Omit; export declare function doSomething_Actual(a: T): { [P in keyof PartialProperties]: PartialProperties[P]; }; +}>(a: T): PartialProperties extends infer T_1 ? { [P in keyof T_1]: PartialProperties[P]; } : never; export declare function doSomething_Expected(a: T): { From 5d51cf7bfdb27ed6bc99f16b7ffc9470e5716aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 19 Mar 2023 19:54:32 +0100 Subject: [PATCH 3/4] Avoid rewriting mapped types without a target --- src/compiler/checker.ts | 2 +- .../baselines/reference/mappedTypeUnionConstraintInferences.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 42e6f322ea03c..80c09b3acb444 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6615,7 +6615,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type: MappedType) { - if (!isMappedTypeWithKeyofConstraintDeclaration(type)) { + if (!type.target || !isMappedTypeWithKeyofConstraintDeclaration(type)) { return false; } const index = getIndexType(getModifiersTypeFromMappedType(type)); diff --git a/tests/baselines/reference/mappedTypeUnionConstraintInferences.js b/tests/baselines/reference/mappedTypeUnionConstraintInferences.js index 7d1602718c18b..7d9e714d339bc 100644 --- a/tests/baselines/reference/mappedTypeUnionConstraintInferences.js +++ b/tests/baselines/reference/mappedTypeUnionConstraintInferences.js @@ -38,7 +38,7 @@ export declare type Omit = Pick>; export declare type PartialProperties = Partial> & Omit; export declare function doSomething_Actual(a: T): PartialProperties extends infer T_1 ? { [P in keyof T_1]: PartialProperties[P]; } : never; +}>(a: T): { [P in keyof PartialProperties]: PartialProperties[P]; }; export declare function doSomething_Expected(a: T): { From 587d9e776ee0566a0b3c3e203d48f59f554d5aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 20 Mar 2023 22:24:41 +0100 Subject: [PATCH 4/4] implemented suggested changes --- src/compiler/checker.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b427763649aed..6781e1d8443dc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6624,12 +6624,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeToTypeNodeHelper(type, context); } + function isMappedTypeHomomorphic(type: MappedType) { + return !!getHomomorphicTypeVariable(type); + } + function isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type: MappedType) { - if (!type.target || !isMappedTypeWithKeyofConstraintDeclaration(type)) { - return false; - } - const index = getIndexType(getModifiersTypeFromMappedType(type)); - return !(index.flags & TypeFlags.Index && (index as IndexType).type.flags & TypeFlags.TypeParameter); + return !!type.target && isMappedTypeHomomorphic(type.target as MappedType) && !isMappedTypeHomomorphic(type); } function createMappedTypeNodeFromType(type: MappedType) {