From ce56eb6c905a5c90480c55b942c55401a86d4a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 4 Dec 2024 18:59:54 +0100 Subject: [PATCH 1/5] Improve relationship check between indexed access types --- src/compiler/checker.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 397a424ee7b27..4ff77c7193379 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23085,10 +23085,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (targetFlags & TypeFlags.IndexedAccess) { if (sourceFlags & TypeFlags.IndexedAccess) { + let objectType = (source as IndexedAccessType).objectType; + let indexType = (source as IndexedAccessType).indexType; + while (objectType.flags & TypeFlags.IndexedAccess && !isGenericIndexType(indexType)) { + const type = getIndexedAccessTypeOrUndefined(getReducedApparentType(objectType), indexType); + if (!type) { + break; + } + if (!(type.flags & TypeFlags.IndexedAccess)) { + if (result = isRelatedTo(type, target, RecursionFlags.Both, reportErrors)) { + return result; + } + break; + } + objectType = (type as IndexedAccessType).objectType; + indexType = (type as IndexedAccessType).indexType; + } // Relate components directly before falling back to constraint relationships // A type S[K] is related to a type T[J] if S is related to T and K is related to J. - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, reportErrors); + if (result = isRelatedTo(objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, reportErrors)) { + result &= isRelatedTo(indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, reportErrors); } if (result) { return result; From 96bcac22230d7ee7a6a160042cc15645a739bd9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 4 Dec 2024 19:50:26 +0100 Subject: [PATCH 2/5] use a better type breakdown --- src/compiler/checker.ts | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4ff77c7193379..a376adbff97ca 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23085,22 +23085,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (targetFlags & TypeFlags.IndexedAccess) { if (sourceFlags & TypeFlags.IndexedAccess) { - let objectType = (source as IndexedAccessType).objectType; - let indexType = (source as IndexedAccessType).indexType; - while (objectType.flags & TypeFlags.IndexedAccess && !isGenericIndexType(indexType)) { - const type = getIndexedAccessTypeOrUndefined(getReducedApparentType(objectType), indexType); - if (!type) { - break; - } - if (!(type.flags & TypeFlags.IndexedAccess)) { - if (result = isRelatedTo(type, target, RecursionFlags.Both, reportErrors)) { - return result; - } - break; - } - objectType = (type as IndexedAccessType).objectType; - indexType = (type as IndexedAccessType).indexType; - } + const objectType = (source as IndexedAccessType).objectType; + const indexType = (source as IndexedAccessType).indexType; // Relate components directly before falling back to constraint relationships // A type S[K] is related to a type T[J] if S is related to T and K is related to J. if (result = isRelatedTo(objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, reportErrors)) { @@ -23112,6 +23098,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (reportErrors) { originalErrorInfo = errorInfo; } + if (objectType.flags & TypeFlags.IndexedAccess && !isGenericIndexType(indexType)) { + const type = getIndexedAccessTypeOrUndefined(getReducedApparentType(objectType), indexType); + if (type && type !== source && (result = isRelatedTo(type, target, RecursionFlags.Both, reportErrors))) { + return result; + } + if (reportErrors) { + originalErrorInfo = errorInfo; + } + } } // A type S is related to a type T[K] if S is related to C, where C is the base // constraint of T[K] for writing. From e7ffdfd608c230248fe5269ce39981e66d3505fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 4 Dec 2024 19:52:54 +0100 Subject: [PATCH 3/5] add test --- .../mappedTypeGenericIndexedAccess2.symbols | 82 +++++++++++++++++ .../mappedTypeGenericIndexedAccess2.types | 88 +++++++++++++++++++ .../mappedTypeGenericIndexedAccess2.ts | 33 +++++++ 3 files changed, 203 insertions(+) create mode 100644 tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols create mode 100644 tests/baselines/reference/mappedTypeGenericIndexedAccess2.types create mode 100644 tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols new file mode 100644 index 0000000000000..dd2fdccdbcb95 --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols @@ -0,0 +1,82 @@ +//// [tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts] //// + +=== mappedTypeGenericIndexedAccess2.ts === +// https://github.com/microsoft/TypeScript/issues/60675 + +type EventPayloads = { +>EventPayloads : Symbol(EventPayloads, Decl(mappedTypeGenericIndexedAccess2.ts, 0, 0)) + + completeSprint: { +>completeSprint : Symbol(completeSprint, Decl(mappedTypeGenericIndexedAccess2.ts, 2, 22)) + + automationId: string; +>automationId : Symbol(automationId, Decl(mappedTypeGenericIndexedAccess2.ts, 3, 19)) + + spaceId: string; +>spaceId : Symbol(spaceId, Decl(mappedTypeGenericIndexedAccess2.ts, 4, 25)) + + }; + sendMessage: { +>sendMessage : Symbol(sendMessage, Decl(mappedTypeGenericIndexedAccess2.ts, 6, 4)) + + message: string; +>message : Symbol(message, Decl(mappedTypeGenericIndexedAccess2.ts, 7, 16)) + + }; +}; + +type CompletedEvent = { +>CompletedEvent : Symbol(CompletedEvent, Decl(mappedTypeGenericIndexedAccess2.ts, 10, 2)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess2.ts, 12, 20)) +>EventPayloads : Symbol(EventPayloads, Decl(mappedTypeGenericIndexedAccess2.ts, 0, 0)) + + [E in T]: { +>E : Symbol(E, Decl(mappedTypeGenericIndexedAccess2.ts, 13, 3)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess2.ts, 12, 20)) + + type: E; +>type : Symbol(type, Decl(mappedTypeGenericIndexedAccess2.ts, 13, 13)) +>E : Symbol(E, Decl(mappedTypeGenericIndexedAccess2.ts, 13, 3)) + + payload: EventPayloads[E]; +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) +>EventPayloads : Symbol(EventPayloads, Decl(mappedTypeGenericIndexedAccess2.ts, 0, 0)) +>E : Symbol(E, Decl(mappedTypeGenericIndexedAccess2.ts, 13, 3)) + + appName: string; +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess2.ts, 15, 30)) + + }; +}[T]; +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess2.ts, 12, 20)) + +function overwriteAppName( +>overwriteAppName : Symbol(overwriteAppName, Decl(mappedTypeGenericIndexedAccess2.ts, 18, 5)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess2.ts, 20, 26)) +>EventPayloads : Symbol(EventPayloads, Decl(mappedTypeGenericIndexedAccess2.ts, 0, 0)) + + scheduled: CompletedEvent, +>scheduled : Symbol(scheduled, Decl(mappedTypeGenericIndexedAccess2.ts, 20, 57)) +>CompletedEvent : Symbol(CompletedEvent, Decl(mappedTypeGenericIndexedAccess2.ts, 10, 2)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess2.ts, 20, 26)) + +): CompletedEvent { +>CompletedEvent : Symbol(CompletedEvent, Decl(mappedTypeGenericIndexedAccess2.ts, 10, 2)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess2.ts, 20, 26)) + + const { appName, ...rest } = scheduled; +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess2.ts, 23, 9)) +>rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess2.ts, 23, 18)) +>scheduled : Symbol(scheduled, Decl(mappedTypeGenericIndexedAccess2.ts, 20, 57)) + + // ok + return { + ...rest, +>rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess2.ts, 23, 18)) + + appName: "test", +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess2.ts, 26, 12)) + + }; +} + diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types new file mode 100644 index 0000000000000..d848822291c5a --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types @@ -0,0 +1,88 @@ +//// [tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts] //// + +=== mappedTypeGenericIndexedAccess2.ts === +// https://github.com/microsoft/TypeScript/issues/60675 + +type EventPayloads = { +>EventPayloads : EventPayloads +> : ^^^^^^^^^^^^^ + + completeSprint: { +>completeSprint : { automationId: string; spaceId: string; } +> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^ + + automationId: string; +>automationId : string +> : ^^^^^^ + + spaceId: string; +>spaceId : string +> : ^^^^^^ + + }; + sendMessage: { +>sendMessage : { message: string; } +> : ^^^^^^^^^^^ ^^^ + + message: string; +>message : string +> : ^^^^^^ + + }; +}; + +type CompletedEvent = { +>CompletedEvent : CompletedEvent +> : ^^^^^^^^^^^^^^^^^ + + [E in T]: { + type: E; +>type : E +> : ^ + + payload: EventPayloads[E]; +>payload : EventPayloads[E] +> : ^^^^^^^^^^^^^^^^ + + appName: string; +>appName : string +> : ^^^^^^ + + }; +}[T]; + +function overwriteAppName( +>overwriteAppName : (scheduled: CompletedEvent) => CompletedEvent +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ + + scheduled: CompletedEvent, +>scheduled : CompletedEvent +> : ^^^^^^^^^^^^^^^^^ + +): CompletedEvent { + const { appName, ...rest } = scheduled; +>appName : string +> : ^^^^^^ +>rest : Omit, "appName"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>scheduled : CompletedEvent +> : ^^^^^^^^^^^^^^^^^ + + // ok + return { +>{ ...rest, appName: "test", } : Omit, "appName"> & { appName: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...rest, +>rest : Omit, "appName"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + appName: "test", +>appName : string +> : ^^^^^^ +>"test" : "test" +> : ^^^^^^ + + }; +} + diff --git a/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts b/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts new file mode 100644 index 0000000000000..b09dfa29b97a0 --- /dev/null +++ b/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts @@ -0,0 +1,33 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/60675 + +type EventPayloads = { + completeSprint: { + automationId: string; + spaceId: string; + }; + sendMessage: { + message: string; + }; +}; + +type CompletedEvent = { + [E in T]: { + type: E; + payload: EventPayloads[E]; + appName: string; + }; +}[T]; + +function overwriteAppName( + scheduled: CompletedEvent, +): CompletedEvent { + const { appName, ...rest } = scheduled; + // ok + return { + ...rest, + appName: "test", + }; +} From f969bcf8c0464d0d9438e3082185aa94e76c8c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 5 Dec 2024 10:01:17 +0100 Subject: [PATCH 4/5] add nested test case --- .../mappedTypeGenericIndexedAccess3.symbols | 138 ++++++++++++++++ .../mappedTypeGenericIndexedAccess3.types | 150 ++++++++++++++++++ .../mappedTypeGenericIndexedAccess3.ts | 51 ++++++ 3 files changed, 339 insertions(+) create mode 100644 tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols create mode 100644 tests/baselines/reference/mappedTypeGenericIndexedAccess3.types create mode 100644 tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols new file mode 100644 index 0000000000000..646cf868d5d6d --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols @@ -0,0 +1,138 @@ +//// [tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts] //// + +=== mappedTypeGenericIndexedAccess3.ts === +type EventPayloads = { +>EventPayloads : Symbol(EventPayloads, Decl(mappedTypeGenericIndexedAccess3.ts, 0, 0)) + + completeSprint: { +>completeSprint : Symbol(completeSprint, Decl(mappedTypeGenericIndexedAccess3.ts, 0, 22)) + + automationId: string; +>automationId : Symbol(automationId, Decl(mappedTypeGenericIndexedAccess3.ts, 1, 19)) + + spaceId: string; +>spaceId : Symbol(spaceId, Decl(mappedTypeGenericIndexedAccess3.ts, 2, 25)) + + }; + sendMessage: { +>sendMessage : Symbol(sendMessage, Decl(mappedTypeGenericIndexedAccess3.ts, 4, 4)) + + message: string; +>message : Symbol(message, Decl(mappedTypeGenericIndexedAccess3.ts, 5, 16)) + + }; +}; + +type Nested = { +>Nested : Symbol(Nested, Decl(mappedTypeGenericIndexedAccess3.ts, 8, 2)) + + bar: { +>bar : Symbol(bar, Decl(mappedTypeGenericIndexedAccess3.ts, 10, 15)) + + a: string; +>a : Symbol(a, Decl(mappedTypeGenericIndexedAccess3.ts, 11, 8)) + + }; + baz: { +>baz : Symbol(baz, Decl(mappedTypeGenericIndexedAccess3.ts, 13, 4)) + + b: string; +>b : Symbol(b, Decl(mappedTypeGenericIndexedAccess3.ts, 14, 8)) + + }; +}; + +type CompletedEvent = { +>CompletedEvent : Symbol(CompletedEvent, Decl(mappedTypeGenericIndexedAccess3.ts, 17, 2)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess3.ts, 19, 20)) +>EventPayloads : Symbol(EventPayloads, Decl(mappedTypeGenericIndexedAccess3.ts, 0, 0)) +>Z : Symbol(Z, Decl(mappedTypeGenericIndexedAccess3.ts, 19, 50)) +>Nested : Symbol(Nested, Decl(mappedTypeGenericIndexedAccess3.ts, 8, 2)) + + [E in T]: { +>E : Symbol(E, Decl(mappedTypeGenericIndexedAccess3.ts, 20, 3)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess3.ts, 19, 20)) + + type: E; +>type : Symbol(type, Decl(mappedTypeGenericIndexedAccess3.ts, 20, 13)) +>E : Symbol(E, Decl(mappedTypeGenericIndexedAccess3.ts, 20, 3)) + + payload: { +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 21, 12)) + + [K in Z]: { +>K : Symbol(K, Decl(mappedTypeGenericIndexedAccess3.ts, 23, 7)) +>Z : Symbol(Z, Decl(mappedTypeGenericIndexedAccess3.ts, 19, 50)) + + other: string; +>other : Symbol(other, Decl(mappedTypeGenericIndexedAccess3.ts, 23, 17)) + + nested: Nested[K]; +>nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) +>Nested : Symbol(Nested, Decl(mappedTypeGenericIndexedAccess3.ts, 8, 2)) +>K : Symbol(K, Decl(mappedTypeGenericIndexedAccess3.ts, 23, 7)) + + }; + }[Z]; +>Z : Symbol(Z, Decl(mappedTypeGenericIndexedAccess3.ts, 19, 50)) + + appName: string; +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess3.ts, 27, 9)) + + }; +}[T]; +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess3.ts, 19, 20)) + +function overwriteAppName< +>overwriteAppName : Symbol(overwriteAppName, Decl(mappedTypeGenericIndexedAccess3.ts, 30, 5)) + + U extends keyof EventPayloads, +>U : Symbol(U, Decl(mappedTypeGenericIndexedAccess3.ts, 32, 26)) +>EventPayloads : Symbol(EventPayloads, Decl(mappedTypeGenericIndexedAccess3.ts, 0, 0)) + + Z extends keyof Nested, +>Z : Symbol(Z, Decl(mappedTypeGenericIndexedAccess3.ts, 33, 32)) +>Nested : Symbol(Nested, Decl(mappedTypeGenericIndexedAccess3.ts, 8, 2)) + +>(scheduled: CompletedEvent): CompletedEvent { +>scheduled : Symbol(scheduled, Decl(mappedTypeGenericIndexedAccess3.ts, 35, 2)) +>CompletedEvent : Symbol(CompletedEvent, Decl(mappedTypeGenericIndexedAccess3.ts, 17, 2)) +>U : Symbol(U, Decl(mappedTypeGenericIndexedAccess3.ts, 32, 26)) +>Z : Symbol(Z, Decl(mappedTypeGenericIndexedAccess3.ts, 33, 32)) +>CompletedEvent : Symbol(CompletedEvent, Decl(mappedTypeGenericIndexedAccess3.ts, 17, 2)) +>U : Symbol(U, Decl(mappedTypeGenericIndexedAccess3.ts, 32, 26)) +>Z : Symbol(Z, Decl(mappedTypeGenericIndexedAccess3.ts, 33, 32)) + + const { appName, type, ...rest } = scheduled; +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess3.ts, 36, 9)) +>type : Symbol(type, Decl(mappedTypeGenericIndexedAccess3.ts, 36, 18)) +>rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess3.ts, 36, 24)) +>scheduled : Symbol(scheduled, Decl(mappedTypeGenericIndexedAccess3.ts, 35, 2)) + + const { other, ...restrest } = rest.payload; +>other : Symbol(other, Decl(mappedTypeGenericIndexedAccess3.ts, 37, 9)) +>restrest : Symbol(restrest, Decl(mappedTypeGenericIndexedAccess3.ts, 37, 16)) +>rest.payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 21, 12)) +>rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess3.ts, 36, 24)) +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 21, 12)) + + return { + type, +>type : Symbol(type, Decl(mappedTypeGenericIndexedAccess3.ts, 39, 10)) + + payload: { +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 40, 9)) + + ...restrest, +>restrest : Symbol(restrest, Decl(mappedTypeGenericIndexedAccess3.ts, 37, 16)) + + other, +>other : Symbol(other, Decl(mappedTypeGenericIndexedAccess3.ts, 42, 18)) + + }, + appName: "test", +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess3.ts, 44, 6)) + + }; +} + diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types new file mode 100644 index 0000000000000..d62aab660be63 --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types @@ -0,0 +1,150 @@ +//// [tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts] //// + +=== mappedTypeGenericIndexedAccess3.ts === +type EventPayloads = { +>EventPayloads : EventPayloads +> : ^^^^^^^^^^^^^ + + completeSprint: { +>completeSprint : { automationId: string; spaceId: string; } +> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^ + + automationId: string; +>automationId : string +> : ^^^^^^ + + spaceId: string; +>spaceId : string +> : ^^^^^^ + + }; + sendMessage: { +>sendMessage : { message: string; } +> : ^^^^^^^^^^^ ^^^ + + message: string; +>message : string +> : ^^^^^^ + + }; +}; + +type Nested = { +>Nested : Nested +> : ^^^^^^ + + bar: { +>bar : { a: string; } +> : ^^^^^ ^^^ + + a: string; +>a : string +> : ^^^^^^ + + }; + baz: { +>baz : { b: string; } +> : ^^^^^ ^^^ + + b: string; +>b : string +> : ^^^^^^ + + }; +}; + +type CompletedEvent = { +>CompletedEvent : CompletedEvent +> : ^^^^^^^^^^^^^^^^^^^^ + + [E in T]: { + type: E; +>type : E +> : ^ + + payload: { +>payload : { [K in Z]: { other: string; nested: Nested[K]; }; }[Z] +> : ^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^ + + [K in Z]: { + other: string; +>other : string +> : ^^^^^^ + + nested: Nested[K]; +>nested : Nested[K] +> : ^^^^^^^^^ + + }; + }[Z]; + appName: string; +>appName : string +> : ^^^^^^ + + }; +}[T]; + +function overwriteAppName< +>overwriteAppName : (scheduled: CompletedEvent) => CompletedEvent +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ + + U extends keyof EventPayloads, + Z extends keyof Nested, +>(scheduled: CompletedEvent): CompletedEvent { +>scheduled : CompletedEvent +> : ^^^^^^^^^^^^^^^^^^^^ + + const { appName, type, ...rest } = scheduled; +>appName : string +> : ^^^^^^ +>type : U +> : ^ +>rest : Omit, "appName" | "type"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>scheduled : CompletedEvent +> : ^^^^^^^^^^^^^^^^^^^^ + + const { other, ...restrest } = rest.payload; +>other : string +> : ^^^^^^ +>restrest : Omit["payload"], "other"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>rest.payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>rest : Omit, "appName" | "type"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return { +>{ type, payload: { ...restrest, other, }, appName: "test", } : { type: U; payload: Omit["payload"], "other"> & { other: string; }; appName: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + type, +>type : U +> : ^ + + payload: { +>payload : Omit["payload"], "other"> & { other: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ ...restrest, other, } : Omit["payload"], "other"> & { other: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...restrest, +>restrest : Omit["payload"], "other"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + other, +>other : string +> : ^^^^^^ + + }, + appName: "test", +>appName : string +> : ^^^^^^ +>"test" : "test" +> : ^^^^^^ + + }; +} + diff --git a/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts b/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts new file mode 100644 index 0000000000000..aa9ba2d23175d --- /dev/null +++ b/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts @@ -0,0 +1,51 @@ +// @strict: true +// @noEmit: true + +type EventPayloads = { + completeSprint: { + automationId: string; + spaceId: string; + }; + sendMessage: { + message: string; + }; +}; + +type Nested = { + bar: { + a: string; + }; + baz: { + b: string; + }; +}; + +type CompletedEvent = { + [E in T]: { + type: E; + payload: { + [K in Z]: { + other: string; + nested: Nested[K]; + }; + }[Z]; + appName: string; + }; +}[T]; + +function overwriteAppName< + U extends keyof EventPayloads, + Z extends keyof Nested, +>(scheduled: CompletedEvent): CompletedEvent { + const { appName, type, ...rest } = scheduled; + const { other, ...restrest } = rest.payload; + + return { + type, + payload: { + ...restrest, + other, + }, + appName: "test", + }; +} From 22a9d531878a93b534f932605b6babb6667029bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 5 Dec 2024 10:25:44 +0100 Subject: [PATCH 5/5] add extra assignment tests --- .../mappedTypeGenericIndexedAccess2.symbols | 18 ++++++++- .../mappedTypeGenericIndexedAccess2.types | 32 +++++++++++++++ .../mappedTypeGenericIndexedAccess3.symbols | 28 +++++++++++-- .../mappedTypeGenericIndexedAccess3.types | 40 +++++++++++++++++++ .../mappedTypeGenericIndexedAccess2.ts | 4 ++ .../mappedTypeGenericIndexedAccess3.ts | 3 ++ 6 files changed, 120 insertions(+), 5 deletions(-) diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols index dd2fdccdbcb95..d352bab0dac33 100644 --- a/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols @@ -69,13 +69,29 @@ function overwriteAppName( >rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess2.ts, 23, 18)) >scheduled : Symbol(scheduled, Decl(mappedTypeGenericIndexedAccess2.ts, 20, 57)) + scheduled.payload = rest.payload // ok +>scheduled.payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) +>scheduled : Symbol(scheduled, Decl(mappedTypeGenericIndexedAccess2.ts, 20, 57)) +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) +>rest.payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) +>rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess2.ts, 23, 18)) +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) + + rest.payload = scheduled.payload // ok +>rest.payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) +>rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess2.ts, 23, 18)) +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) +>scheduled.payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) +>scheduled : Symbol(scheduled, Decl(mappedTypeGenericIndexedAccess2.ts, 20, 57)) +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess2.ts, 14, 12)) + // ok return { ...rest, >rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess2.ts, 23, 18)) appName: "test", ->appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess2.ts, 26, 12)) +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess2.ts, 30, 12)) }; } diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types index d848822291c5a..25d04928b99e8 100644 --- a/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types @@ -68,6 +68,38 @@ function overwriteAppName( >scheduled : CompletedEvent > : ^^^^^^^^^^^^^^^^^ + scheduled.payload = rest.payload // ok +>scheduled.payload = rest.payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>scheduled.payload : EventPayloads[T] +> : ^^^^^^^^^^^^^^^^ +>scheduled : CompletedEvent +> : ^^^^^^^^^^^^^^^^^ +>payload : EventPayloads[T] +> : ^^^^^^^^^^^^^^^^ +>rest.payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>rest : Omit, "appName"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + rest.payload = scheduled.payload // ok +>rest.payload = scheduled.payload : EventPayloads[T] +> : ^^^^^^^^^^^^^^^^ +>rest.payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>rest : Omit, "appName"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>scheduled.payload : EventPayloads[T] +> : ^^^^^^^^^^^^^^^^ +>scheduled : CompletedEvent +> : ^^^^^^^^^^^^^^^^^ +>payload : EventPayloads[T] +> : ^^^^^^^^^^^^^^^^ + // ok return { >{ ...rest, appName: "test", } : Omit, "appName"> & { appName: string; } diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols index 646cf868d5d6d..518eac1021958 100644 --- a/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols @@ -116,22 +116,42 @@ function overwriteAppName< >rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess3.ts, 36, 24)) >payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 21, 12)) + rest.payload.nested = restrest.nested; // ok +>rest.payload.nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) +>rest.payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 21, 12)) +>rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess3.ts, 36, 24)) +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 21, 12)) +>nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) +>restrest.nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) +>restrest : Symbol(restrest, Decl(mappedTypeGenericIndexedAccess3.ts, 37, 16)) +>nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) + + restrest.nested = rest.payload.nested; // ok +>restrest.nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) +>restrest : Symbol(restrest, Decl(mappedTypeGenericIndexedAccess3.ts, 37, 16)) +>nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) +>rest.payload.nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) +>rest.payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 21, 12)) +>rest : Symbol(rest, Decl(mappedTypeGenericIndexedAccess3.ts, 36, 24)) +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 21, 12)) +>nested : Symbol(nested, Decl(mappedTypeGenericIndexedAccess3.ts, 24, 22)) + return { type, ->type : Symbol(type, Decl(mappedTypeGenericIndexedAccess3.ts, 39, 10)) +>type : Symbol(type, Decl(mappedTypeGenericIndexedAccess3.ts, 42, 10)) payload: { ->payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 40, 9)) +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 43, 9)) ...restrest, >restrest : Symbol(restrest, Decl(mappedTypeGenericIndexedAccess3.ts, 37, 16)) other, ->other : Symbol(other, Decl(mappedTypeGenericIndexedAccess3.ts, 42, 18)) +>other : Symbol(other, Decl(mappedTypeGenericIndexedAccess3.ts, 45, 18)) }, appName: "test", ->appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess3.ts, 44, 6)) +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess3.ts, 47, 6)) }; } diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types index d62aab660be63..9a53149be7d96 100644 --- a/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types @@ -116,6 +116,46 @@ function overwriteAppName< >payload : CompletedEvent["payload"] > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + rest.payload.nested = restrest.nested; // ok +>rest.payload.nested = restrest.nested : CompletedEvent["payload"]["nested"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>rest.payload.nested : Nested[Z] +> : ^^^^^^^^^ +>rest.payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>rest : Omit, "appName" | "type"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>nested : Nested[Z] +> : ^^^^^^^^^ +>restrest.nested : CompletedEvent["payload"]["nested"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>restrest : Omit["payload"], "other"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>nested : CompletedEvent["payload"]["nested"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + restrest.nested = rest.payload.nested; // ok +>restrest.nested = rest.payload.nested : Nested[Z] +> : ^^^^^^^^^ +>restrest.nested : CompletedEvent["payload"]["nested"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>restrest : Omit["payload"], "other"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>nested : CompletedEvent["payload"]["nested"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>rest.payload.nested : Nested[Z] +> : ^^^^^^^^^ +>rest.payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>rest : Omit, "appName" | "type"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>payload : CompletedEvent["payload"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>nested : Nested[Z] +> : ^^^^^^^^^ + return { >{ type, payload: { ...restrest, other, }, appName: "test", } : { type: U; payload: Omit["payload"], "other"> & { other: string; }; appName: string; } > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts b/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts index b09dfa29b97a0..d962890485430 100644 --- a/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts +++ b/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts @@ -25,6 +25,10 @@ function overwriteAppName( scheduled: CompletedEvent, ): CompletedEvent { const { appName, ...rest } = scheduled; + + scheduled.payload = rest.payload // ok + rest.payload = scheduled.payload // ok + // ok return { ...rest, diff --git a/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts b/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts index aa9ba2d23175d..2cb0065c1057b 100644 --- a/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts +++ b/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts @@ -40,6 +40,9 @@ function overwriteAppName< const { appName, type, ...rest } = scheduled; const { other, ...restrest } = rest.payload; + rest.payload.nested = restrest.nested; // ok + restrest.nested = rest.payload.nested; // ok + return { type, payload: {