diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 397a424ee7b27..a376adbff97ca 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23085,10 +23085,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (targetFlags & TypeFlags.IndexedAccess) { if (sourceFlags & TypeFlags.IndexedAccess) { + 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((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; @@ -23096,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. diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols new file mode 100644 index 0000000000000..d352bab0dac33 --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.symbols @@ -0,0 +1,98 @@ +//// [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)) + + 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, 30, 12)) + + }; +} + diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types new file mode 100644 index 0000000000000..25d04928b99e8 --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess2.types @@ -0,0 +1,120 @@ +//// [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 +> : ^^^^^^^^^^^^^^^^^ + + 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; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...rest, +>rest : Omit, "appName"> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + appName: "test", +>appName : string +> : ^^^^^^ +>"test" : "test" +> : ^^^^^^ + + }; +} + diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols new file mode 100644 index 0000000000000..518eac1021958 --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.symbols @@ -0,0 +1,158 @@ +//// [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)) + + 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, 42, 10)) + + payload: { +>payload : Symbol(payload, Decl(mappedTypeGenericIndexedAccess3.ts, 43, 9)) + + ...restrest, +>restrest : Symbol(restrest, Decl(mappedTypeGenericIndexedAccess3.ts, 37, 16)) + + other, +>other : Symbol(other, Decl(mappedTypeGenericIndexedAccess3.ts, 45, 18)) + + }, + appName: "test", +>appName : Symbol(appName, Decl(mappedTypeGenericIndexedAccess3.ts, 47, 6)) + + }; +} + diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types new file mode 100644 index 0000000000000..9a53149be7d96 --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess3.types @@ -0,0 +1,190 @@ +//// [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"] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + 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; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + 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/mappedTypeGenericIndexedAccess2.ts b/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts new file mode 100644 index 0000000000000..d962890485430 --- /dev/null +++ b/tests/cases/compiler/mappedTypeGenericIndexedAccess2.ts @@ -0,0 +1,37 @@ +// @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; + + scheduled.payload = rest.payload // ok + rest.payload = scheduled.payload // ok + + // ok + return { + ...rest, + appName: "test", + }; +} diff --git a/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts b/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts new file mode 100644 index 0000000000000..2cb0065c1057b --- /dev/null +++ b/tests/cases/compiler/mappedTypeGenericIndexedAccess3.ts @@ -0,0 +1,54 @@ +// @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; + + rest.payload.nested = restrest.nested; // ok + restrest.nested = rest.payload.nested; // ok + + return { + type, + payload: { + ...restrest, + other, + }, + appName: "test", + }; +}