diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 018539b1b0e..c24040ec31f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10537,11 +10537,14 @@ namespace ts { } } // A type S is assignable to keyof T if S is assignable to keyof C, where C is the - // constraint of T. - const constraint = getConstraintForRelation((target).type); - if (constraint) { - if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors)) { - return result; + // simplified form of T or, if T doesn't simplify, the constraint of T. + if (relation !== definitelyAssignableRelation) { + const simplified = getSimplifiedType((target).type); + const constraint = simplified !== (target).type ? simplified : getConstraintOfType((target).type); + if (constraint) { + if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors)) { + return result; + } } } } diff --git a/tests/baselines/reference/keyofAndIndexedAccess.js b/tests/baselines/reference/keyofAndIndexedAccess.js index f0af336563c..a343b1e24fc 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.js +++ b/tests/baselines/reference/keyofAndIndexedAccess.js @@ -566,6 +566,15 @@ type Predicates = { [T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T] } +// Repros from #23592 + +type Example = { [K in keyof T]: T[K]["prop"] }; +type Result = Example<{ a: { prop: string }; b: { prop: number } }>; + +type Helper2 = { [K in keyof T]: Extract }; +type Example2 = { [K in keyof Helper2]: Helper2[K]["prop"] }; +type Result2 = Example2<{ 1: { prop: string }; 2: { prop: number } }>; + // Repro from #23618 type DBBoolTable = { [k in K]: 0 | 1 } @@ -1241,6 +1250,37 @@ declare function f3>(t: T, k: K, tk: T[K]) declare type Predicates = { [T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T]; }; +declare type Example = { + [K in keyof T]: T[K]["prop"]; +}; +declare type Result = Example<{ + a: { + prop: string; + }; + b: { + prop: number; + }; +}>; +declare type Helper2 = { + [K in keyof T]: Extract; +}; +declare type Example2 = { + [K in keyof Helper2]: Helper2[K]["prop"]; +}; +declare type Result2 = Example2<{ + 1: { + prop: string; + }; + 2: { + prop: number; + }; +}>; declare type DBBoolTable = { [k in K]: 0 | 1; }; diff --git a/tests/baselines/reference/keyofAndIndexedAccess.symbols b/tests/baselines/reference/keyofAndIndexedAccess.symbols index 27c7128e42d..5c0b45d81fb 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.symbols +++ b/tests/baselines/reference/keyofAndIndexedAccess.symbols @@ -2010,64 +2010,113 @@ type Predicates = { >T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 564, 3)) } +// Repros from #23592 + +type Example = { [K in keyof T]: T[K]["prop"] }; +>Example : Symbol(Example, Decl(keyofAndIndexedAccess.ts, 565, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 569, 13)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 569, 26)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 569, 13)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 569, 42)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 569, 63)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 569, 13)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 569, 13)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 569, 63)) + +type Result = Example<{ a: { prop: string }; b: { prop: number } }>; +>Result : Symbol(Result, Decl(keyofAndIndexedAccess.ts, 569, 93)) +>Example : Symbol(Example, Decl(keyofAndIndexedAccess.ts, 565, 1)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 570, 23)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 570, 28)) +>b : Symbol(b, Decl(keyofAndIndexedAccess.ts, 570, 44)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 570, 49)) + +type Helper2 = { [K in keyof T]: Extract }; +>Helper2 : Symbol(Helper2, Decl(keyofAndIndexedAccess.ts, 570, 68)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 572, 13)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 572, 21)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 572, 13)) +>Extract : Symbol(Extract, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 572, 13)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 572, 21)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 572, 51)) + +type Example2 = { [K in keyof Helper2]: Helper2[K]["prop"] }; +>Example2 : Symbol(Example2, Decl(keyofAndIndexedAccess.ts, 572, 67)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 573, 14)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 573, 22)) +>Helper2 : Symbol(Helper2, Decl(keyofAndIndexedAccess.ts, 570, 68)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 573, 14)) +>Helper2 : Symbol(Helper2, Decl(keyofAndIndexedAccess.ts, 570, 68)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 573, 14)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 573, 22)) + +type Result2 = Example2<{ 1: { prop: string }; 2: { prop: number } }>; +>Result2 : Symbol(Result2, Decl(keyofAndIndexedAccess.ts, 573, 70)) +>Example2 : Symbol(Example2, Decl(keyofAndIndexedAccess.ts, 572, 67)) +>1 : Symbol(1, Decl(keyofAndIndexedAccess.ts, 574, 25)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 574, 30)) +>2 : Symbol(2, Decl(keyofAndIndexedAccess.ts, 574, 46)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 574, 51)) + // Repro from #23618 type DBBoolTable = { [k in K]: 0 | 1 } ->DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 565, 1)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 569, 17)) ->k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 569, 40)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 569, 17)) +>DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 574, 70)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 578, 17)) +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 578, 40)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 578, 17)) enum Flag { ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 569, 56)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 578, 56)) FLAG_1 = "flag_1", ->FLAG_1 : Symbol(Flag.FLAG_1, Decl(keyofAndIndexedAccess.ts, 570, 11)) +>FLAG_1 : Symbol(Flag.FLAG_1, Decl(keyofAndIndexedAccess.ts, 579, 11)) FLAG_2 = "flag_2" ->FLAG_2 : Symbol(Flag.FLAG_2, Decl(keyofAndIndexedAccess.ts, 571, 22)) +>FLAG_2 : Symbol(Flag.FLAG_2, Decl(keyofAndIndexedAccess.ts, 580, 22)) } type SimpleDBRecord = { staticField: number } & DBBoolTable ->SimpleDBRecord : Symbol(SimpleDBRecord, Decl(keyofAndIndexedAccess.ts, 573, 1)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 575, 20)) ->staticField : Symbol(staticField, Decl(keyofAndIndexedAccess.ts, 575, 44)) ->DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 565, 1)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 575, 20)) +>SimpleDBRecord : Symbol(SimpleDBRecord, Decl(keyofAndIndexedAccess.ts, 582, 1)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 584, 20)) +>staticField : Symbol(staticField, Decl(keyofAndIndexedAccess.ts, 584, 44)) +>DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 574, 70)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 584, 20)) function getFlagsFromSimpleRecord(record: SimpleDBRecord, flags: Flag[]) { ->getFlagsFromSimpleRecord : Symbol(getFlagsFromSimpleRecord, Decl(keyofAndIndexedAccess.ts, 575, 86)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 576, 34)) ->record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 576, 55)) ->SimpleDBRecord : Symbol(SimpleDBRecord, Decl(keyofAndIndexedAccess.ts, 573, 1)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 576, 34)) ->flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 576, 84)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 576, 34)) +>getFlagsFromSimpleRecord : Symbol(getFlagsFromSimpleRecord, Decl(keyofAndIndexedAccess.ts, 584, 86)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 585, 34)) +>record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 585, 55)) +>SimpleDBRecord : Symbol(SimpleDBRecord, Decl(keyofAndIndexedAccess.ts, 582, 1)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 585, 34)) +>flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 585, 84)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 585, 34)) return record[flags[0]]; ->record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 576, 55)) ->flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 576, 84)) +>record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 585, 55)) +>flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 585, 84)) } type DynamicDBRecord = ({ dynamicField: number } | { dynamicField: string }) & DBBoolTable ->DynamicDBRecord : Symbol(DynamicDBRecord, Decl(keyofAndIndexedAccess.ts, 578, 1)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 580, 21)) ->dynamicField : Symbol(dynamicField, Decl(keyofAndIndexedAccess.ts, 580, 46)) ->dynamicField : Symbol(dynamicField, Decl(keyofAndIndexedAccess.ts, 580, 73)) ->DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 565, 1)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 580, 21)) +>DynamicDBRecord : Symbol(DynamicDBRecord, Decl(keyofAndIndexedAccess.ts, 587, 1)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 589, 21)) +>dynamicField : Symbol(dynamicField, Decl(keyofAndIndexedAccess.ts, 589, 46)) +>dynamicField : Symbol(dynamicField, Decl(keyofAndIndexedAccess.ts, 589, 73)) +>DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 574, 70)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 589, 21)) function getFlagsFromDynamicRecord(record: DynamicDBRecord, flags: Flag[]) { ->getFlagsFromDynamicRecord : Symbol(getFlagsFromDynamicRecord, Decl(keyofAndIndexedAccess.ts, 580, 117)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 581, 35)) ->record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 581, 56)) ->DynamicDBRecord : Symbol(DynamicDBRecord, Decl(keyofAndIndexedAccess.ts, 578, 1)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 581, 35)) ->flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 581, 86)) ->Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 581, 35)) +>getFlagsFromDynamicRecord : Symbol(getFlagsFromDynamicRecord, Decl(keyofAndIndexedAccess.ts, 589, 117)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 590, 35)) +>record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 590, 56)) +>DynamicDBRecord : Symbol(DynamicDBRecord, Decl(keyofAndIndexedAccess.ts, 587, 1)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 590, 35)) +>flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 590, 86)) +>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 590, 35)) return record[flags[0]]; ->record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 581, 56)) ->flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 581, 86)) +>record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 590, 56)) +>flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 590, 86)) } diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index de35c620d33..51b91526fdb 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -2345,6 +2345,55 @@ type Predicates = { >T : T } +// Repros from #23592 + +type Example = { [K in keyof T]: T[K]["prop"] }; +>Example : Example +>T : T +>K : K +>T : T +>prop : any +>K : K +>T : T +>T : T +>K : K + +type Result = Example<{ a: { prop: string }; b: { prop: number } }>; +>Result : Example<{ a: { prop: string; }; b: { prop: number; }; }> +>Example : Example +>a : { prop: string; } +>prop : string +>b : { prop: number; } +>prop : number + +type Helper2 = { [K in keyof T]: Extract }; +>Helper2 : Helper2 +>T : T +>K : K +>T : T +>Extract : Extract +>T : T +>K : K +>prop : any + +type Example2 = { [K in keyof Helper2]: Helper2[K]["prop"] }; +>Example2 : Example2 +>T : T +>K : K +>Helper2 : Helper2 +>T : T +>Helper2 : Helper2 +>T : T +>K : K + +type Result2 = Example2<{ 1: { prop: string }; 2: { prop: number } }>; +>Result2 : Example2<{ 1: { prop: string; }; 2: { prop: number; }; }> +>Example2 : Example2 +>1 : { prop: string; } +>prop : string +>2 : { prop: number; } +>prop : number + // Repro from #23618 type DBBoolTable = { [k in K]: 0 | 1 } diff --git a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts index 03d4ae01ea1..23e5cd6a66e 100644 --- a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts +++ b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts @@ -568,6 +568,15 @@ type Predicates = { [T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T] } +// Repros from #23592 + +type Example = { [K in keyof T]: T[K]["prop"] }; +type Result = Example<{ a: { prop: string }; b: { prop: number } }>; + +type Helper2 = { [K in keyof T]: Extract }; +type Example2 = { [K in keyof Helper2]: Helper2[K]["prop"] }; +type Result2 = Example2<{ 1: { prop: string }; 2: { prop: number } }>; + // Repro from #23618 type DBBoolTable = { [k in K]: 0 | 1 }