diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1931661bf5f7c..c476297bb68b0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7987,7 +7987,8 @@ namespace ts { } function getIndexType(type: Type): Type { - return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type) : + return type.flags & TypeFlags.Intersection ? getUnionType(map((type).types, t => getIndexType(t))) : + maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type) : getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(type) : type === wildcardType ? wildcardType : type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : diff --git a/tests/baselines/reference/indexedAccessRelation.types b/tests/baselines/reference/indexedAccessRelation.types index 2564a82702dd6..02884d8682a17 100644 --- a/tests/baselines/reference/indexedAccessRelation.types +++ b/tests/baselines/reference/indexedAccessRelation.types @@ -44,9 +44,9 @@ class Comp extends Component> this.setState({ a: a }); >this.setState({ a: a }) : void ->this.setState : )>(state: Pick, K>) => void +>this.setState : (state: Pick, K>) => void >this : this ->setState : )>(state: Pick, K>) => void +>setState : (state: Pick, K>) => void >{ a: a } : { a: T; } >a : T >a : T diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index af441e865ff22..694abf7d10e56 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -888,20 +888,20 @@ function f60(source: T, target: T) { } function f70(func: (k1: keyof (T | U), k2: keyof (T & U)) => void) { ->f70 : (func: (k1: keyof (T | U), k2: keyof (T & U)) => void) => void ->func : (k1: keyof (T | U), k2: keyof (T & U)) => void +>f70 : (func: (k1: keyof (T | U), k2: keyof T | keyof U) => void) => void +>func : (k1: keyof (T | U), k2: keyof T | keyof U) => void >T : T >U : U >k1 : keyof (T | U) >T : T >U : U ->k2 : keyof (T & U) +>k2 : keyof T | keyof U >T : T >U : U func<{ a: any, b: any }, { a: any, c: any }>('a', 'a'); >func<{ a: any, b: any }, { a: any, c: any }>('a', 'a') : void ->func : (k1: keyof (T | U), k2: keyof (T & U)) => void +>func : (k1: keyof (T | U), k2: keyof T | keyof U) => void >a : any >b : any >a : any @@ -911,7 +911,7 @@ function f70(func: (k1: keyof (T | U), k2: keyof (T & U)) => void) { func<{ a: any, b: any }, { a: any, c: any }>('a', 'b'); >func<{ a: any, b: any }, { a: any, c: any }>('a', 'b') : void ->func : (k1: keyof (T | U), k2: keyof (T & U)) => void +>func : (k1: keyof (T | U), k2: keyof T | keyof U) => void >a : any >b : any >a : any @@ -921,7 +921,7 @@ function f70(func: (k1: keyof (T | U), k2: keyof (T & U)) => void) { func<{ a: any, b: any }, { a: any, c: any }>('a', 'c'); >func<{ a: any, b: any }, { a: any, c: any }>('a', 'c') : void ->func : (k1: keyof (T | U), k2: keyof (T & U)) => void +>func : (k1: keyof (T | U), k2: keyof T | keyof U) => void >a : any >b : any >a : any @@ -1034,8 +1034,8 @@ function f72(func: (x: T, y: U, k: K) => (T & } function f73(func: (x: T, y: U, k: K) => (T & U)[K]) { ->f73 : (func: (x: T, y: U, k: K) => (T & U)[K]) => void ->func : (x: T, y: U, k: K) => (T & U)[K] +>f73 : (func: (x: T, y: U, k: K) => (T & U)[K]) => void +>func : (x: T, y: U, k: K) => (T & U)[K] >T : T >U : U >K : K @@ -1054,7 +1054,7 @@ function f73(func: (x: T, y: U, k: K) => (T & U)[ let a = func({ a: 1, b: "hello" }, { c: true }, 'a'); // number >a : number >func({ a: 1, b: "hello" }, { c: true }, 'a') : number ->func : (x: T, y: U, k: K) => (T & U)[K] +>func : (x: T, y: U, k: K) => (T & U)[K] >{ a: 1, b: "hello" } : { a: number; b: string; } >a : number >1 : 1 @@ -1068,7 +1068,7 @@ function f73(func: (x: T, y: U, k: K) => (T & U)[ let b = func({ a: 1, b: "hello" }, { c: true }, 'b'); // string >b : string >func({ a: 1, b: "hello" }, { c: true }, 'b') : string ->func : (x: T, y: U, k: K) => (T & U)[K] +>func : (x: T, y: U, k: K) => (T & U)[K] >{ a: 1, b: "hello" } : { a: number; b: string; } >a : number >1 : 1 @@ -1082,7 +1082,7 @@ function f73(func: (x: T, y: U, k: K) => (T & U)[ let c = func({ a: 1, b: "hello" }, { c: true }, 'c'); // boolean >c : boolean >func({ a: 1, b: "hello" }, { c: true }, 'c') : boolean ->func : (x: T, y: U, k: K) => (T & U)[K] +>func : (x: T, y: U, k: K) => (T & U)[K] >{ a: 1, b: "hello" } : { a: number; b: string; } >a : number >1 : 1 @@ -1837,7 +1837,7 @@ declare class Component1 { >Computed : Computed get(key: K): (Data & Computed)[K]; ->get : (key: K) => (Data & Computed)[K] +>get : (key: K) => (Data & Computed)[K] >K : K >Data : Data >Computed : Computed @@ -2035,9 +2035,9 @@ function onChangeGenericFunction(handler: Handler) { handler.onChange('preset') >handler.onChange('preset') : void ->handler.onChange : (name: keyof (T & { preset: number; })) => void +>handler.onChange : (name: keyof T | "preset") => void >handler : Handler ->onChange : (name: keyof (T & { preset: number; })) => void +>onChange : (name: keyof T | "preset") => void >'preset' : "preset" } diff --git a/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt b/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt index 0b2da3f8e6107..49f44115e72fc 100644 --- a/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt @@ -22,11 +22,12 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(64,33): error tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(66,24): error TS2345: Argument of type '"size"' is not assignable to parameter of type '"name" | "width" | "height" | "visible"'. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(67,24): error TS2345: Argument of type '"name" | "size"' is not assignable to parameter of type '"name" | "width" | "height" | "visible"'. Type '"size"' is not assignable to type '"name" | "width" | "height" | "visible"'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(72,5): error TS2536: Type 'keyof (T & U)' cannot be used to index type 'T | U'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(72,5): error TS2536: Type 'keyof T | keyof U' cannot be used to index type 'T | U'. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(76,5): error TS2322: Type 'T | U' is not assignable to type 'T & U'. Type 'T' is not assignable to type 'T & U'. Type 'T' is not assignable to type 'U'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(77,5): error TS2322: Type 'keyof (T & U)' is not assignable to type 'keyof (T | U)'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(77,5): error TS2322: Type 'keyof T | keyof U' is not assignable to type 'keyof (T | U)'. + Type 'keyof T' is not assignable to type 'keyof (T | U)'. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(86,9): error TS2322: Type 'keyof T' is not assignable to type 'K'. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(88,9): error TS2322: Type 'T[keyof T]' is not assignable to type 'T[K]'. Type 'keyof T' is not assignable to type 'K'. @@ -161,7 +162,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(100,5): error o1[k1]; o1[k2]; // Error ~~~~~~ -!!! error TS2536: Type 'keyof (T & U)' cannot be used to index type 'T | U'. +!!! error TS2536: Type 'keyof T | keyof U' cannot be used to index type 'T | U'. o2[k1]; o2[k2]; o1 = o2; @@ -172,7 +173,8 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(100,5): error !!! error TS2322: Type 'T' is not assignable to type 'U'. k1 = k2; // Error ~~ -!!! error TS2322: Type 'keyof (T & U)' is not assignable to type 'keyof (T | U)'. +!!! error TS2322: Type 'keyof T | keyof U' is not assignable to type 'keyof (T | U)'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'keyof (T | U)'. k2 = k1; } diff --git a/tests/baselines/reference/keyofAndIndexedAccessErrors.types b/tests/baselines/reference/keyofAndIndexedAccessErrors.types index 0c51d3a575c12..bcd3878013d24 100644 --- a/tests/baselines/reference/keyofAndIndexedAccessErrors.types +++ b/tests/baselines/reference/keyofAndIndexedAccessErrors.types @@ -243,13 +243,13 @@ function f10(shape: Shape) { } function f20(k1: keyof (T | U), k2: keyof (T & U), o1: T | U, o2: T & U) { ->f20 : (k1: keyof (T | U), k2: keyof (T & U), o1: T | U, o2: T & U) => void +>f20 : (k1: keyof (T | U), k2: keyof T | keyof U, o1: T | U, o2: T & U) => void >T : T >U : U >k1 : keyof (T | U) >T : T >U : U ->k2 : keyof (T & U) +>k2 : keyof T | keyof U >T : T >U : U >o1 : T | U @@ -265,9 +265,9 @@ function f20(k1: keyof (T | U), k2: keyof (T & U), o1: T | U, o2: T & U) { >k1 : keyof (T | U) o1[k2]; // Error ->o1[k2] : (T | U)[keyof (T & U)] +>o1[k2] : (T | U)[keyof T | keyof U] >o1 : T | U ->k2 : keyof (T & U) +>k2 : keyof T | keyof U o2[k1]; >o2[k1] : (T & U)[keyof (T | U)] @@ -275,9 +275,9 @@ function f20(k1: keyof (T | U), k2: keyof (T & U), o1: T | U, o2: T & U) { >k1 : keyof (T | U) o2[k2]; ->o2[k2] : (T & U)[keyof (T & U)] +>o2[k2] : (T & U)[keyof T | keyof U] >o2 : T & U ->k2 : keyof (T & U) +>k2 : keyof T | keyof U o1 = o2; >o1 = o2 : T & U @@ -290,13 +290,13 @@ function f20(k1: keyof (T | U), k2: keyof (T & U), o1: T | U, o2: T & U) { >o1 : T | U k1 = k2; // Error ->k1 = k2 : keyof (T & U) +>k1 = k2 : keyof T | keyof U >k1 : keyof (T | U) ->k2 : keyof (T & U) +>k2 : keyof T | keyof U k2 = k1; >k2 = k1 : keyof (T | U) ->k2 : keyof (T & U) +>k2 : keyof T | keyof U >k1 : keyof (T | U) } diff --git a/tests/baselines/reference/keyofIntersection.js b/tests/baselines/reference/keyofIntersection.js new file mode 100644 index 0000000000000..3b6fc7eea1b72 --- /dev/null +++ b/tests/baselines/reference/keyofIntersection.js @@ -0,0 +1,56 @@ +//// [keyofIntersection.ts] +type A = { a: string }; +type B = { b: string }; + +type T01 = keyof (A & B); // "a" | "b" +type T02 = keyof (T & B); // "b" | keyof T +type T03 = keyof (A & U); // "a" | keyof U +type T04 = keyof (T & U); // keyof T | keyof U +type T05 = T02; // "a" | "b" +type T06 = T03; // "a" | "b" +type T07 = T04; // "a" | "b" + +// Repros from #22291 + +type Example1 = keyof (Record & Record); +type Result1 = Example1<'x', 'y'>; // "x" | "y" + +type Result2 = keyof (Record<'x', any> & Record<'y', any>); // "x" | "y" + +type Example3 = keyof (Record); +type Result3 = Example3<'x' | 'y'>; // "x" | "y" + +type Example4 = (Record & Record); +type Result4 = keyof Example4<'x', 'y'>; // "x" | "y" + +type Example5 = keyof (T & U); +type Result5 = Example5, Record<'y', any>>; // "x" | "y" + + +//// [keyofIntersection.js] +"use strict"; + + +//// [keyofIntersection.d.ts] +declare type A = { + a: string; +}; +declare type B = { + b: string; +}; +declare type T01 = keyof (A & B); +declare type T02 = keyof (T & B); +declare type T03 = keyof (A & U); +declare type T04 = keyof (T & U); +declare type T05 = T02; +declare type T06 = T03; +declare type T07 = T04; +declare type Example1 = keyof (Record & Record); +declare type Result1 = Example1<'x', 'y'>; +declare type Result2 = keyof (Record<'x', any> & Record<'y', any>); +declare type Example3 = keyof (Record); +declare type Result3 = Example3<'x' | 'y'>; +declare type Example4 = (Record & Record); +declare type Result4 = keyof Example4<'x', 'y'>; +declare type Example5 = keyof (T & U); +declare type Result5 = Example5, Record<'y', any>>; diff --git a/tests/baselines/reference/keyofIntersection.symbols b/tests/baselines/reference/keyofIntersection.symbols new file mode 100644 index 0000000000000..aac8341f36350 --- /dev/null +++ b/tests/baselines/reference/keyofIntersection.symbols @@ -0,0 +1,105 @@ +=== tests/cases/conformance/types/keyof/keyofIntersection.ts === +type A = { a: string }; +>A : Symbol(A, Decl(keyofIntersection.ts, 0, 0)) +>a : Symbol(a, Decl(keyofIntersection.ts, 0, 10)) + +type B = { b: string }; +>B : Symbol(B, Decl(keyofIntersection.ts, 0, 23)) +>b : Symbol(b, Decl(keyofIntersection.ts, 1, 10)) + +type T01 = keyof (A & B); // "a" | "b" +>T01 : Symbol(T01, Decl(keyofIntersection.ts, 1, 23)) +>A : Symbol(A, Decl(keyofIntersection.ts, 0, 0)) +>B : Symbol(B, Decl(keyofIntersection.ts, 0, 23)) + +type T02 = keyof (T & B); // "b" | keyof T +>T02 : Symbol(T02, Decl(keyofIntersection.ts, 3, 25)) +>T : Symbol(T, Decl(keyofIntersection.ts, 4, 9)) +>T : Symbol(T, Decl(keyofIntersection.ts, 4, 9)) +>B : Symbol(B, Decl(keyofIntersection.ts, 0, 23)) + +type T03 = keyof (A & U); // "a" | keyof U +>T03 : Symbol(T03, Decl(keyofIntersection.ts, 4, 28)) +>U : Symbol(U, Decl(keyofIntersection.ts, 5, 9)) +>A : Symbol(A, Decl(keyofIntersection.ts, 0, 0)) +>U : Symbol(U, Decl(keyofIntersection.ts, 5, 9)) + +type T04 = keyof (T & U); // keyof T | keyof U +>T04 : Symbol(T04, Decl(keyofIntersection.ts, 5, 28)) +>T : Symbol(T, Decl(keyofIntersection.ts, 6, 9)) +>U : Symbol(U, Decl(keyofIntersection.ts, 6, 11)) +>T : Symbol(T, Decl(keyofIntersection.ts, 6, 9)) +>U : Symbol(U, Decl(keyofIntersection.ts, 6, 11)) + +type T05 = T02; // "a" | "b" +>T05 : Symbol(T05, Decl(keyofIntersection.ts, 6, 31)) +>T02 : Symbol(T02, Decl(keyofIntersection.ts, 3, 25)) +>A : Symbol(A, Decl(keyofIntersection.ts, 0, 0)) + +type T06 = T03; // "a" | "b" +>T06 : Symbol(T06, Decl(keyofIntersection.ts, 7, 18)) +>T03 : Symbol(T03, Decl(keyofIntersection.ts, 4, 28)) +>B : Symbol(B, Decl(keyofIntersection.ts, 0, 23)) + +type T07 = T04; // "a" | "b" +>T07 : Symbol(T07, Decl(keyofIntersection.ts, 8, 18)) +>T04 : Symbol(T04, Decl(keyofIntersection.ts, 5, 28)) +>A : Symbol(A, Decl(keyofIntersection.ts, 0, 0)) +>B : Symbol(B, Decl(keyofIntersection.ts, 0, 23)) + +// Repros from #22291 + +type Example1 = keyof (Record & Record); +>Example1 : Symbol(Example1, Decl(keyofIntersection.ts, 9, 21)) +>T : Symbol(T, Decl(keyofIntersection.ts, 13, 14)) +>U : Symbol(U, Decl(keyofIntersection.ts, 13, 31)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(keyofIntersection.ts, 13, 14)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>U : Symbol(U, Decl(keyofIntersection.ts, 13, 31)) + +type Result1 = Example1<'x', 'y'>; // "x" | "y" +>Result1 : Symbol(Result1, Decl(keyofIntersection.ts, 13, 92)) +>Example1 : Symbol(Example1, Decl(keyofIntersection.ts, 9, 21)) + +type Result2 = keyof (Record<'x', any> & Record<'y', any>); // "x" | "y" +>Result2 : Symbol(Result2, Decl(keyofIntersection.ts, 14, 34)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) + +type Example3 = keyof (Record); +>Example3 : Symbol(Example3, Decl(keyofIntersection.ts, 16, 59)) +>T : Symbol(T, Decl(keyofIntersection.ts, 18, 14)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(keyofIntersection.ts, 18, 14)) + +type Result3 = Example3<'x' | 'y'>; // "x" | "y" +>Result3 : Symbol(Result3, Decl(keyofIntersection.ts, 18, 57)) +>Example3 : Symbol(Example3, Decl(keyofIntersection.ts, 16, 59)) + +type Example4 = (Record & Record); +>Example4 : Symbol(Example4, Decl(keyofIntersection.ts, 19, 35)) +>T : Symbol(T, Decl(keyofIntersection.ts, 21, 14)) +>U : Symbol(U, Decl(keyofIntersection.ts, 21, 31)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(keyofIntersection.ts, 21, 14)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>U : Symbol(U, Decl(keyofIntersection.ts, 21, 31)) + +type Result4 = keyof Example4<'x', 'y'>; // "x" | "y" +>Result4 : Symbol(Result4, Decl(keyofIntersection.ts, 21, 86)) +>Example4 : Symbol(Example4, Decl(keyofIntersection.ts, 19, 35)) + +type Example5 = keyof (T & U); +>Example5 : Symbol(Example5, Decl(keyofIntersection.ts, 22, 40)) +>T : Symbol(T, Decl(keyofIntersection.ts, 24, 14)) +>U : Symbol(U, Decl(keyofIntersection.ts, 24, 16)) +>T : Symbol(T, Decl(keyofIntersection.ts, 24, 14)) +>U : Symbol(U, Decl(keyofIntersection.ts, 24, 16)) + +type Result5 = Example5, Record<'y', any>>; // "x" | "y" +>Result5 : Symbol(Result5, Decl(keyofIntersection.ts, 24, 36)) +>Example5 : Symbol(Example5, Decl(keyofIntersection.ts, 22, 40)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/keyofIntersection.types b/tests/baselines/reference/keyofIntersection.types new file mode 100644 index 0000000000000..f9c312b412046 --- /dev/null +++ b/tests/baselines/reference/keyofIntersection.types @@ -0,0 +1,105 @@ +=== tests/cases/conformance/types/keyof/keyofIntersection.ts === +type A = { a: string }; +>A : A +>a : string + +type B = { b: string }; +>B : B +>b : string + +type T01 = keyof (A & B); // "a" | "b" +>T01 : "b" | "a" +>A : A +>B : B + +type T02 = keyof (T & B); // "b" | keyof T +>T02 : keyof T | "b" +>T : T +>T : T +>B : B + +type T03 = keyof (A & U); // "a" | keyof U +>T03 : "a" | keyof U +>U : U +>A : A +>U : U + +type T04 = keyof (T & U); // keyof T | keyof U +>T04 : keyof T | keyof U +>T : T +>U : U +>T : T +>U : U + +type T05 = T02; // "a" | "b" +>T05 : "b" | "a" +>T02 : keyof T | "b" +>A : A + +type T06 = T03; // "a" | "b" +>T06 : "b" | "a" +>T03 : "a" | keyof U +>B : B + +type T07 = T04; // "a" | "b" +>T07 : "b" | "a" +>T04 : keyof T | keyof U +>A : A +>B : B + +// Repros from #22291 + +type Example1 = keyof (Record & Record); +>Example1 : T | U +>T : T +>U : U +>Record : Record +>T : T +>Record : Record +>U : U + +type Result1 = Example1<'x', 'y'>; // "x" | "y" +>Result1 : "x" | "y" +>Example1 : T | U + +type Result2 = keyof (Record<'x', any> & Record<'y', any>); // "x" | "y" +>Result2 : "x" | "y" +>Record : Record +>Record : Record + +type Example3 = keyof (Record); +>Example3 : T +>T : T +>Record : Record +>T : T + +type Result3 = Example3<'x' | 'y'>; // "x" | "y" +>Result3 : "x" | "y" +>Example3 : T + +type Example4 = (Record & Record); +>Example4 : Record & Record +>T : T +>U : U +>Record : Record +>T : T +>Record : Record +>U : U + +type Result4 = keyof Example4<'x', 'y'>; // "x" | "y" +>Result4 : "x" | "y" +>Example4 : Record & Record + +type Example5 = keyof (T & U); +>Example5 : keyof T | keyof U +>T : T +>U : U +>T : T +>U : U + +type Result5 = Example5, Record<'y', any>>; // "x" | "y" +>Result5 : "x" | "y" +>Example5 : keyof T | keyof U +>Record : Record +>Record : Record + diff --git a/tests/cases/conformance/types/keyof/keyofIntersection.ts b/tests/cases/conformance/types/keyof/keyofIntersection.ts new file mode 100644 index 0000000000000..f570a873242e0 --- /dev/null +++ b/tests/cases/conformance/types/keyof/keyofIntersection.ts @@ -0,0 +1,29 @@ +// @strict: true +// @declaration: true + +type A = { a: string }; +type B = { b: string }; + +type T01 = keyof (A & B); // "a" | "b" +type T02 = keyof (T & B); // "b" | keyof T +type T03 = keyof (A & U); // "a" | keyof U +type T04 = keyof (T & U); // keyof T | keyof U +type T05 = T02; // "a" | "b" +type T06 = T03; // "a" | "b" +type T07 = T04; // "a" | "b" + +// Repros from #22291 + +type Example1 = keyof (Record & Record); +type Result1 = Example1<'x', 'y'>; // "x" | "y" + +type Result2 = keyof (Record<'x', any> & Record<'y', any>); // "x" | "y" + +type Example3 = keyof (Record); +type Result3 = Example3<'x' | 'y'>; // "x" | "y" + +type Example4 = (Record & Record); +type Result4 = keyof Example4<'x', 'y'>; // "x" | "y" + +type Example5 = keyof (T & U); +type Result5 = Example5, Record<'y', any>>; // "x" | "y"