From 3ba5aa9f60437467e7d7042e67499a8acd5233ba Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 11 Mar 2019 15:41:05 -0700 Subject: [PATCH] Add regression test for #29692 (#30325) --- .../reference/deepKeysIndexing.errors.txt | 68 ++++++ tests/baselines/reference/deepKeysIndexing.js | 72 +++++++ .../reference/deepKeysIndexing.symbols | 193 ++++++++++++++++++ .../reference/deepKeysIndexing.types | 119 +++++++++++ tests/cases/compiler/deepKeysIndexing.ts | 55 +++++ 5 files changed, 507 insertions(+) create mode 100644 tests/baselines/reference/deepKeysIndexing.errors.txt create mode 100644 tests/baselines/reference/deepKeysIndexing.js create mode 100644 tests/baselines/reference/deepKeysIndexing.symbols create mode 100644 tests/baselines/reference/deepKeysIndexing.types create mode 100644 tests/cases/compiler/deepKeysIndexing.ts diff --git a/tests/baselines/reference/deepKeysIndexing.errors.txt b/tests/baselines/reference/deepKeysIndexing.errors.txt new file mode 100644 index 0000000000000..a1711d92c70c0 --- /dev/null +++ b/tests/baselines/reference/deepKeysIndexing.errors.txt @@ -0,0 +1,68 @@ +tests/cases/compiler/deepKeysIndexing.ts(53,22): error TS2345: Argument of type 'true' is not assignable to parameter of type '123'. +tests/cases/compiler/deepKeysIndexing.ts(54,23): error TS2345: Argument of type 'true' is not assignable to parameter of type '123'. +tests/cases/compiler/deepKeysIndexing.ts(55,26): error TS2345: Argument of type 'true' is not assignable to parameter of type '123'. + + +==== tests/cases/compiler/deepKeysIndexing.ts (3 errors) ==== + // regression test from https://github.com/Microsoft/TypeScript/issues/29692 + interface DeepObject { + [k1: string]: { + [k2: string]: any; + }; + } + + type keys2broken< + O extends DeepObject, + K1 extends keyof O + > = O[K1] extends object ? Extract : never; + + type keys2working< + O extends DeepObject, + K1 extends keyof O + > = O[K1] extends object ? keyof O[K1] : never; + + type keys2workaround = Extract< + O[K1] extends object ? keyof O[K1] : never, + string + >; + + interface Foo extends DeepObject { + a: { + "1": 123; + "2": string; + "3": boolean; + }; + } + + class Bar { + broken< + K1 extends keyof O, + K2 extends keys2broken, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} + + working< + K1 extends keyof O, + K2 extends keys2working, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} + + workaround< + K1 extends keyof O, + K2 extends keys2workaround, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} + } + + const bar = new Bar(); + // all 3 of the below should error on passing `true` for `"1"` + bar.broken("a", "1", true); // was broken in the past - with 2nd argument incorrectly of type "1" | "2" | "3". + ~~~~ +!!! error TS2345: Argument of type 'true' is not assignable to parameter of type '123'. + bar.working("a", "1", true); // ok - true is not allowed + ~~~~ +!!! error TS2345: Argument of type 'true' is not assignable to parameter of type '123'. + bar.workaround("a", "1", true); // ok - true is not allowed + ~~~~ +!!! error TS2345: Argument of type 'true' is not assignable to parameter of type '123'. + \ No newline at end of file diff --git a/tests/baselines/reference/deepKeysIndexing.js b/tests/baselines/reference/deepKeysIndexing.js new file mode 100644 index 0000000000000..b19a9ce4b20a1 --- /dev/null +++ b/tests/baselines/reference/deepKeysIndexing.js @@ -0,0 +1,72 @@ +//// [deepKeysIndexing.ts] +// regression test from https://github.com/Microsoft/TypeScript/issues/29692 +interface DeepObject { + [k1: string]: { + [k2: string]: any; + }; +} + +type keys2broken< + O extends DeepObject, + K1 extends keyof O +> = O[K1] extends object ? Extract : never; + +type keys2working< + O extends DeepObject, + K1 extends keyof O +> = O[K1] extends object ? keyof O[K1] : never; + +type keys2workaround = Extract< + O[K1] extends object ? keyof O[K1] : never, + string +>; + +interface Foo extends DeepObject { + a: { + "1": 123; + "2": string; + "3": boolean; + }; +} + +class Bar { + broken< + K1 extends keyof O, + K2 extends keys2broken, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} + + working< + K1 extends keyof O, + K2 extends keys2working, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} + + workaround< + K1 extends keyof O, + K2 extends keys2workaround, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} +} + +const bar = new Bar(); +// all 3 of the below should error on passing `true` for `"1"` +bar.broken("a", "1", true); // was broken in the past - with 2nd argument incorrectly of type "1" | "2" | "3". +bar.working("a", "1", true); // ok - true is not allowed +bar.workaround("a", "1", true); // ok - true is not allowed + + +//// [deepKeysIndexing.js] +var Bar = /** @class */ (function () { + function Bar() { + } + Bar.prototype.broken = function (k1, k2, value) { }; + Bar.prototype.working = function (k1, k2, value) { }; + Bar.prototype.workaround = function (k1, k2, value) { }; + return Bar; +}()); +var bar = new Bar(); +// all 3 of the below should error on passing `true` for `"1"` +bar.broken("a", "1", true); // was broken in the past - with 2nd argument incorrectly of type "1" | "2" | "3". +bar.working("a", "1", true); // ok - true is not allowed +bar.workaround("a", "1", true); // ok - true is not allowed diff --git a/tests/baselines/reference/deepKeysIndexing.symbols b/tests/baselines/reference/deepKeysIndexing.symbols new file mode 100644 index 0000000000000..0bb66df3a07b4 --- /dev/null +++ b/tests/baselines/reference/deepKeysIndexing.symbols @@ -0,0 +1,193 @@ +=== tests/cases/compiler/deepKeysIndexing.ts === +// regression test from https://github.com/Microsoft/TypeScript/issues/29692 +interface DeepObject { +>DeepObject : Symbol(DeepObject, Decl(deepKeysIndexing.ts, 0, 0)) + + [k1: string]: { +>k1 : Symbol(k1, Decl(deepKeysIndexing.ts, 2, 3)) + + [k2: string]: any; +>k2 : Symbol(k2, Decl(deepKeysIndexing.ts, 3, 5)) + + }; +} + +type keys2broken< +>keys2broken : Symbol(keys2broken, Decl(deepKeysIndexing.ts, 5, 1)) + + O extends DeepObject, +>O : Symbol(O, Decl(deepKeysIndexing.ts, 7, 17)) +>DeepObject : Symbol(DeepObject, Decl(deepKeysIndexing.ts, 0, 0)) + + K1 extends keyof O +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 8, 23)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 7, 17)) + +> = O[K1] extends object ? Extract : never; +>O : Symbol(O, Decl(deepKeysIndexing.ts, 7, 17)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 8, 23)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 7, 17)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 8, 23)) + +type keys2working< +>keys2working : Symbol(keys2working, Decl(deepKeysIndexing.ts, 10, 64)) + + O extends DeepObject, +>O : Symbol(O, Decl(deepKeysIndexing.ts, 12, 18)) +>DeepObject : Symbol(DeepObject, Decl(deepKeysIndexing.ts, 0, 0)) + + K1 extends keyof O +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 13, 23)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 12, 18)) + +> = O[K1] extends object ? keyof O[K1] : never; +>O : Symbol(O, Decl(deepKeysIndexing.ts, 12, 18)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 13, 23)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 12, 18)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 13, 23)) + +type keys2workaround = Extract< +>keys2workaround : Symbol(keys2workaround, Decl(deepKeysIndexing.ts, 15, 47)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 17, 21)) +>DeepObject : Symbol(DeepObject, Decl(deepKeysIndexing.ts, 0, 0)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 17, 42)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 17, 21)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) + + O[K1] extends object ? keyof O[K1] : never, +>O : Symbol(O, Decl(deepKeysIndexing.ts, 17, 21)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 17, 42)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 17, 21)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 17, 42)) + + string +>; + +interface Foo extends DeepObject { +>Foo : Symbol(Foo, Decl(deepKeysIndexing.ts, 20, 2)) +>DeepObject : Symbol(DeepObject, Decl(deepKeysIndexing.ts, 0, 0)) + + a: { +>a : Symbol(Foo.a, Decl(deepKeysIndexing.ts, 22, 34)) + + "1": 123; +>"1" : Symbol("1", Decl(deepKeysIndexing.ts, 23, 6)) + + "2": string; +>"2" : Symbol("2", Decl(deepKeysIndexing.ts, 24, 13)) + + "3": boolean; +>"3" : Symbol("3", Decl(deepKeysIndexing.ts, 25, 16)) + + }; +} + +class Bar { +>Bar : Symbol(Bar, Decl(deepKeysIndexing.ts, 28, 1)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) +>DeepObject : Symbol(DeepObject, Decl(deepKeysIndexing.ts, 0, 0)) + + broken< +>broken : Symbol(Bar.broken, Decl(deepKeysIndexing.ts, 30, 33)) + + K1 extends keyof O, +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 31, 9)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) + + K2 extends keys2broken, +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 32, 23)) +>keys2broken : Symbol(keys2broken, Decl(deepKeysIndexing.ts, 5, 1)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 31, 9)) + + V extends O[K1][K2] +>V : Symbol(V, Decl(deepKeysIndexing.ts, 33, 34)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 31, 9)) +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 32, 23)) + + >(k1: K1, k2: K2, value: V) {} +>k1 : Symbol(k1, Decl(deepKeysIndexing.ts, 35, 4)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 31, 9)) +>k2 : Symbol(k2, Decl(deepKeysIndexing.ts, 35, 11)) +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 32, 23)) +>value : Symbol(value, Decl(deepKeysIndexing.ts, 35, 19)) +>V : Symbol(V, Decl(deepKeysIndexing.ts, 33, 34)) + + working< +>working : Symbol(Bar.working, Decl(deepKeysIndexing.ts, 35, 32)) + + K1 extends keyof O, +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 37, 10)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) + + K2 extends keys2working, +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 38, 23)) +>keys2working : Symbol(keys2working, Decl(deepKeysIndexing.ts, 10, 64)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 37, 10)) + + V extends O[K1][K2] +>V : Symbol(V, Decl(deepKeysIndexing.ts, 39, 35)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 37, 10)) +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 38, 23)) + + >(k1: K1, k2: K2, value: V) {} +>k1 : Symbol(k1, Decl(deepKeysIndexing.ts, 41, 4)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 37, 10)) +>k2 : Symbol(k2, Decl(deepKeysIndexing.ts, 41, 11)) +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 38, 23)) +>value : Symbol(value, Decl(deepKeysIndexing.ts, 41, 19)) +>V : Symbol(V, Decl(deepKeysIndexing.ts, 39, 35)) + + workaround< +>workaround : Symbol(Bar.workaround, Decl(deepKeysIndexing.ts, 41, 32)) + + K1 extends keyof O, +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 43, 13)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) + + K2 extends keys2workaround, +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 44, 23)) +>keys2workaround : Symbol(keys2workaround, Decl(deepKeysIndexing.ts, 15, 47)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 43, 13)) + + V extends O[K1][K2] +>V : Symbol(V, Decl(deepKeysIndexing.ts, 45, 38)) +>O : Symbol(O, Decl(deepKeysIndexing.ts, 30, 10)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 43, 13)) +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 44, 23)) + + >(k1: K1, k2: K2, value: V) {} +>k1 : Symbol(k1, Decl(deepKeysIndexing.ts, 47, 4)) +>K1 : Symbol(K1, Decl(deepKeysIndexing.ts, 43, 13)) +>k2 : Symbol(k2, Decl(deepKeysIndexing.ts, 47, 11)) +>K2 : Symbol(K2, Decl(deepKeysIndexing.ts, 44, 23)) +>value : Symbol(value, Decl(deepKeysIndexing.ts, 47, 19)) +>V : Symbol(V, Decl(deepKeysIndexing.ts, 45, 38)) +} + +const bar = new Bar(); +>bar : Symbol(bar, Decl(deepKeysIndexing.ts, 50, 5)) +>Bar : Symbol(Bar, Decl(deepKeysIndexing.ts, 28, 1)) +>Foo : Symbol(Foo, Decl(deepKeysIndexing.ts, 20, 2)) + +// all 3 of the below should error on passing `true` for `"1"` +bar.broken("a", "1", true); // was broken in the past - with 2nd argument incorrectly of type "1" | "2" | "3". +>bar.broken : Symbol(Bar.broken, Decl(deepKeysIndexing.ts, 30, 33)) +>bar : Symbol(bar, Decl(deepKeysIndexing.ts, 50, 5)) +>broken : Symbol(Bar.broken, Decl(deepKeysIndexing.ts, 30, 33)) + +bar.working("a", "1", true); // ok - true is not allowed +>bar.working : Symbol(Bar.working, Decl(deepKeysIndexing.ts, 35, 32)) +>bar : Symbol(bar, Decl(deepKeysIndexing.ts, 50, 5)) +>working : Symbol(Bar.working, Decl(deepKeysIndexing.ts, 35, 32)) + +bar.workaround("a", "1", true); // ok - true is not allowed +>bar.workaround : Symbol(Bar.workaround, Decl(deepKeysIndexing.ts, 41, 32)) +>bar : Symbol(bar, Decl(deepKeysIndexing.ts, 50, 5)) +>workaround : Symbol(Bar.workaround, Decl(deepKeysIndexing.ts, 41, 32)) + diff --git a/tests/baselines/reference/deepKeysIndexing.types b/tests/baselines/reference/deepKeysIndexing.types new file mode 100644 index 0000000000000..ba39a7bc29dee --- /dev/null +++ b/tests/baselines/reference/deepKeysIndexing.types @@ -0,0 +1,119 @@ +=== tests/cases/compiler/deepKeysIndexing.ts === +// regression test from https://github.com/Microsoft/TypeScript/issues/29692 +interface DeepObject { + [k1: string]: { +>k1 : string + + [k2: string]: any; +>k2 : string + + }; +} + +type keys2broken< +>keys2broken : keys2broken + + O extends DeepObject, + K1 extends keyof O +> = O[K1] extends object ? Extract : never; + +type keys2working< +>keys2working : keys2working + + O extends DeepObject, + K1 extends keyof O +> = O[K1] extends object ? keyof O[K1] : never; + +type keys2workaround = Extract< +>keys2workaround : Extract + + O[K1] extends object ? keyof O[K1] : never, + string +>; + +interface Foo extends DeepObject { + a: { +>a : { "1": 123; "2": string; "3": boolean; } + + "1": 123; +>"1" : 123 + + "2": string; +>"2" : string + + "3": boolean; +>"3" : boolean + + }; +} + +class Bar { +>Bar : Bar + + broken< +>broken : , V extends O[K1][K2]>(k1: K1, k2: K2, value: V) => void + + K1 extends keyof O, + K2 extends keys2broken, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} +>k1 : K1 +>k2 : K2 +>value : V + + working< +>working : , V extends O[K1][K2]>(k1: K1, k2: K2, value: V) => void + + K1 extends keyof O, + K2 extends keys2working, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} +>k1 : K1 +>k2 : K2 +>value : V + + workaround< +>workaround : , V extends O[K1][K2]>(k1: K1, k2: K2, value: V) => void + + K1 extends keyof O, + K2 extends keys2workaround, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} +>k1 : K1 +>k2 : K2 +>value : V +} + +const bar = new Bar(); +>bar : Bar +>new Bar() : Bar +>Bar : typeof Bar + +// all 3 of the below should error on passing `true` for `"1"` +bar.broken("a", "1", true); // was broken in the past - with 2nd argument incorrectly of type "1" | "2" | "3". +>bar.broken("a", "1", true) : any +>bar.broken : , V extends Foo[K1][K2]>(k1: K1, k2: K2, value: V) => void +>bar : Bar +>broken : , V extends Foo[K1][K2]>(k1: K1, k2: K2, value: V) => void +>"a" : "a" +>"1" : "1" +>true : true + +bar.working("a", "1", true); // ok - true is not allowed +>bar.working("a", "1", true) : any +>bar.working : , V extends Foo[K1][K2]>(k1: K1, k2: K2, value: V) => void +>bar : Bar +>working : , V extends Foo[K1][K2]>(k1: K1, k2: K2, value: V) => void +>"a" : "a" +>"1" : "1" +>true : true + +bar.workaround("a", "1", true); // ok - true is not allowed +>bar.workaround("a", "1", true) : any +>bar.workaround : , V extends Foo[K1][K2]>(k1: K1, k2: K2, value: V) => void +>bar : Bar +>workaround : , V extends Foo[K1][K2]>(k1: K1, k2: K2, value: V) => void +>"a" : "a" +>"1" : "1" +>true : true + diff --git a/tests/cases/compiler/deepKeysIndexing.ts b/tests/cases/compiler/deepKeysIndexing.ts new file mode 100644 index 0000000000000..35f0912e5d5f5 --- /dev/null +++ b/tests/cases/compiler/deepKeysIndexing.ts @@ -0,0 +1,55 @@ +// regression test from https://github.com/Microsoft/TypeScript/issues/29692 +interface DeepObject { + [k1: string]: { + [k2: string]: any; + }; +} + +type keys2broken< + O extends DeepObject, + K1 extends keyof O +> = O[K1] extends object ? Extract : never; + +type keys2working< + O extends DeepObject, + K1 extends keyof O +> = O[K1] extends object ? keyof O[K1] : never; + +type keys2workaround = Extract< + O[K1] extends object ? keyof O[K1] : never, + string +>; + +interface Foo extends DeepObject { + a: { + "1": 123; + "2": string; + "3": boolean; + }; +} + +class Bar { + broken< + K1 extends keyof O, + K2 extends keys2broken, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} + + working< + K1 extends keyof O, + K2 extends keys2working, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} + + workaround< + K1 extends keyof O, + K2 extends keys2workaround, + V extends O[K1][K2] + >(k1: K1, k2: K2, value: V) {} +} + +const bar = new Bar(); +// all 3 of the below should error on passing `true` for `"1"` +bar.broken("a", "1", true); // was broken in the past - with 2nd argument incorrectly of type "1" | "2" | "3". +bar.working("a", "1", true); // ok - true is not allowed +bar.workaround("a", "1", true); // ok - true is not allowed