From fe075f26a26a7813d622044a52505628265d6270 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Fri, 2 Mar 2018 09:11:33 -0800 Subject: [PATCH 1/4] Transform 'keyof (A & B)' to 'keyof A | keyof B' --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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(<InstantiableType | UnionOrIntersectionType>type) : + return type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t))) : + maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type) : getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) : type === wildcardType ? wildcardType : type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : From 4256be1591dcf140d38c0c6fe25e4a6a49bba869 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Fri, 2 Mar 2018 09:24:59 -0800 Subject: [PATCH 2/4] Accept new baselines --- .../reference/indexedAccessRelation.types | 4 +-- .../reference/keyofAndIndexedAccess.types | 28 +++++++++---------- .../keyofAndIndexedAccessErrors.errors.txt | 10 ++++--- .../keyofAndIndexedAccessErrors.types | 18 ++++++------ 4 files changed, 31 insertions(+), 29 deletions(-) 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<T extends Foo, S> extends Component<S & State<T>> this.setState({ a: a }); >this.setState({ a: a }) : void ->this.setState : <K extends keyof (S & State<T>)>(state: Pick<S & State<T>, K>) => void +>this.setState : <K extends keyof S | "a">(state: Pick<S & State<T>, K>) => void >this : this ->setState : <K extends keyof (S & State<T>)>(state: Pick<S & State<T>, K>) => void +>setState : <K extends keyof S | "a">(state: Pick<S & State<T>, 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<T>(source: T, target: T) { } function f70(func: <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void) { ->f70 : (func: <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void) => void ->func : <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void +>f70 : (func: <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void) => void +>func : <T, U>(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 : <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void +>func : <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void >a : any >b : any >a : any @@ -911,7 +911,7 @@ function f70(func: <T, U>(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 : <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void +>func : <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void >a : any >b : any >a : any @@ -921,7 +921,7 @@ function f70(func: <T, U>(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 : <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void +>func : <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void >a : any >b : any >a : any @@ -1034,8 +1034,8 @@ function f72(func: <T, U, K extends keyof T | keyof U>(x: T, y: U, k: K) => (T & } function f73(func: <T, U, K extends keyof (T & U)>(x: T, y: U, k: K) => (T & U)[K]) { ->f73 : (func: <T, U, K extends keyof (T & U)>(x: T, y: U, k: K) => (T & U)[K]) => void ->func : <T, U, K extends keyof (T & U)>(x: T, y: U, k: K) => (T & U)[K] +>f73 : (func: <T, U, K extends keyof T | keyof U>(x: T, y: U, k: K) => (T & U)[K]) => void +>func : <T, U, K extends keyof T | keyof U>(x: T, y: U, k: K) => (T & U)[K] >T : T >U : U >K : K @@ -1054,7 +1054,7 @@ function f73(func: <T, U, K extends keyof (T & U)>(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 : <T, U, K extends keyof (T & U)>(x: T, y: U, k: K) => (T & U)[K] +>func : <T, U, K extends keyof T | keyof U>(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: <T, U, K extends keyof (T & U)>(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 : <T, U, K extends keyof (T & U)>(x: T, y: U, k: K) => (T & U)[K] +>func : <T, U, K extends keyof T | keyof U>(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: <T, U, K extends keyof (T & U)>(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 : <T, U, K extends keyof (T & U)>(x: T, y: U, k: K) => (T & U)[K] +>func : <T, U, K extends keyof T | keyof U>(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<Data, Computed> { >Computed : Computed get<K extends keyof (Data & Computed)>(key: K): (Data & Computed)[K]; ->get : <K extends keyof (Data & Computed)>(key: K) => (Data & Computed)[K] +>get : <K extends keyof Data | keyof Computed>(key: K) => (Data & Computed)[K] >K : K >Data : Data >Computed : Computed @@ -2035,9 +2035,9 @@ function onChangeGenericFunction<T>(handler: Handler<T & {preset: number}>) { handler.onChange('preset') >handler.onChange('preset') : void ->handler.onChange : (name: keyof (T & { preset: number; })) => void +>handler.onChange : (name: keyof T | "preset") => void >handler : Handler<T & { preset: number; }> ->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<T, U>(k1: keyof (T | U), k2: keyof (T & U), o1: T | U, o2: T & U) { ->f20 : <T, U>(k1: keyof (T | U), k2: keyof (T & U), o1: T | U, o2: T & U) => void +>f20 : <T, U>(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<T, U>(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<T, U>(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<T, U>(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) } From 95bb156a3e3064ccc6c0a5fc5a92e652c84a7872 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Fri, 2 Mar 2018 09:26:52 -0800 Subject: [PATCH 3/4] Add tests --- .../types/keyof/keyofIntersection.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/cases/conformance/types/keyof/keyofIntersection.ts 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<T> = keyof (T & B); // "b" | keyof T +type T03<U> = keyof (A & U); // "a" | keyof U +type T04<T, U> = keyof (T & U); // keyof T | keyof U +type T05 = T02<A>; // "a" | "b" +type T06 = T03<B>; // "a" | "b" +type T07 = T04<A, B>; // "a" | "b" + +// Repros from #22291 + +type Example1<T extends string, U extends string> = keyof (Record<T, any> & Record<U, any>); +type Result1 = Example1<'x', 'y'>; // "x" | "y" + +type Result2 = keyof (Record<'x', any> & Record<'y', any>); // "x" | "y" + +type Example3<T extends string> = keyof (Record<T, any>); +type Result3 = Example3<'x' | 'y'>; // "x" | "y" + +type Example4<T extends string, U extends string> = (Record<T, any> & Record<U, any>); +type Result4 = keyof Example4<'x', 'y'>; // "x" | "y" + +type Example5<T, U> = keyof (T & U); +type Result5 = Example5<Record<'x', any>, Record<'y', any>>; // "x" | "y" From 886191390ed413ce70277e70063a5fa65c3fe901 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Fri, 2 Mar 2018 09:27:07 -0800 Subject: [PATCH 4/4] Accept new baselines --- .../baselines/reference/keyofIntersection.js | 56 ++++++++++ .../reference/keyofIntersection.symbols | 105 ++++++++++++++++++ .../reference/keyofIntersection.types | 105 ++++++++++++++++++ 3 files changed, 266 insertions(+) create mode 100644 tests/baselines/reference/keyofIntersection.js create mode 100644 tests/baselines/reference/keyofIntersection.symbols create mode 100644 tests/baselines/reference/keyofIntersection.types 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<T> = keyof (T & B); // "b" | keyof T +type T03<U> = keyof (A & U); // "a" | keyof U +type T04<T, U> = keyof (T & U); // keyof T | keyof U +type T05 = T02<A>; // "a" | "b" +type T06 = T03<B>; // "a" | "b" +type T07 = T04<A, B>; // "a" | "b" + +// Repros from #22291 + +type Example1<T extends string, U extends string> = keyof (Record<T, any> & Record<U, any>); +type Result1 = Example1<'x', 'y'>; // "x" | "y" + +type Result2 = keyof (Record<'x', any> & Record<'y', any>); // "x" | "y" + +type Example3<T extends string> = keyof (Record<T, any>); +type Result3 = Example3<'x' | 'y'>; // "x" | "y" + +type Example4<T extends string, U extends string> = (Record<T, any> & Record<U, any>); +type Result4 = keyof Example4<'x', 'y'>; // "x" | "y" + +type Example5<T, U> = keyof (T & U); +type Result5 = Example5<Record<'x', any>, 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<T> = keyof (T & B); +declare type T03<U> = keyof (A & U); +declare type T04<T, U> = keyof (T & U); +declare type T05 = T02<A>; +declare type T06 = T03<B>; +declare type T07 = T04<A, B>; +declare type Example1<T extends string, U extends string> = keyof (Record<T, any> & Record<U, any>); +declare type Result1 = Example1<'x', 'y'>; +declare type Result2 = keyof (Record<'x', any> & Record<'y', any>); +declare type Example3<T extends string> = keyof (Record<T, any>); +declare type Result3 = Example3<'x' | 'y'>; +declare type Example4<T extends string, U extends string> = (Record<T, any> & Record<U, any>); +declare type Result4 = keyof Example4<'x', 'y'>; +declare type Example5<T, U> = keyof (T & U); +declare type Result5 = Example5<Record<'x', any>, 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<T> = 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<U> = 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<T, U> = 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>; // "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<B>; // "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>; // "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<T extends string, U extends string> = keyof (Record<T, any> & Record<U, any>); +>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<T extends string> = keyof (Record<T, any>); +>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<T extends string, U extends string> = (Record<T, any> & Record<U, any>); +>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<T, U> = 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<'x', any>, 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<T> = keyof (T & B); // "b" | keyof T +>T02 : keyof T | "b" +>T : T +>T : T +>B : B + +type T03<U> = keyof (A & U); // "a" | keyof U +>T03 : "a" | keyof U +>U : U +>A : A +>U : U + +type T04<T, U> = keyof (T & U); // keyof T | keyof U +>T04 : keyof T | keyof U +>T : T +>U : U +>T : T +>U : U + +type T05 = T02<A>; // "a" | "b" +>T05 : "b" | "a" +>T02 : keyof T | "b" +>A : A + +type T06 = T03<B>; // "a" | "b" +>T06 : "b" | "a" +>T03 : "a" | keyof U +>B : B + +type T07 = T04<A, B>; // "a" | "b" +>T07 : "b" | "a" +>T04 : keyof T | keyof U +>A : A +>B : B + +// Repros from #22291 + +type Example1<T extends string, U extends string> = keyof (Record<T, any> & Record<U, any>); +>Example1 : T | U +>T : T +>U : U +>Record : Record<K, T> +>T : T +>Record : Record<K, T> +>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<K, T> +>Record : Record<K, T> + +type Example3<T extends string> = keyof (Record<T, any>); +>Example3 : T +>T : T +>Record : Record<K, T> +>T : T + +type Result3 = Example3<'x' | 'y'>; // "x" | "y" +>Result3 : "x" | "y" +>Example3 : T + +type Example4<T extends string, U extends string> = (Record<T, any> & Record<U, any>); +>Example4 : Record<T, any> & Record<U, any> +>T : T +>U : U +>Record : Record<K, T> +>T : T +>Record : Record<K, T> +>U : U + +type Result4 = keyof Example4<'x', 'y'>; // "x" | "y" +>Result4 : "x" | "y" +>Example4 : Record<T, any> & Record<U, any> + +type Example5<T, U> = keyof (T & U); +>Example5 : keyof T | keyof U +>T : T +>U : U +>T : T +>U : U + +type Result5 = Example5<Record<'x', any>, Record<'y', any>>; // "x" | "y" +>Result5 : "x" | "y" +>Example5 : keyof T | keyof U +>Record : Record<K, T> +>Record : Record<K, T> +