diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.js b/tests/baselines/reference/isomorphicMappedTypeInference.js index 87f3e1c4017..0ed2285ed04 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.js +++ b/tests/baselines/reference/isomorphicMappedTypeInference.js @@ -118,7 +118,32 @@ function f10(foo: Foo) { let x = validate(foo); // { a: number, readonly b: string } let y = clone(foo); // { a?: number, b: string } let z = validateAndClone(foo); // { a: number, b: string } -} +} + +// Repro from #12606 + +type Func = (...args: any[]) => T; +type Spec = { + [P in keyof T]: Func | Spec ; +}; + +/** + * Given a spec object recursively mapping properties to functions, creates a function + * producing an object of the same structure, by mapping each property to the result + * of calling its associated function with the supplied arguments. + */ +declare function applySpec(obj: Spec): (...args: any[]) => T; + +// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } } +var g1 = applySpec({ + sum: (a: any) => 3, + nested: { + mul: (b: any) => "n" + } +}); + +// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } } +var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } }); //// [isomorphicMappedTypeInference.js] function box(x) { @@ -210,6 +235,15 @@ function f10(foo) { var y = clone(foo); // { a?: number, b: string } var z = validateAndClone(foo); // { a: number, b: string } } +// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } } +var g1 = applySpec({ + sum: function (a) { return 3; }, + nested: { + mul: function (b) { return "n"; } + } +}); +// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } } +var g2 = applySpec({ foo: { bar: { baz: function (x) { return true; } } } }); //// [isomorphicMappedTypeInference.d.ts] @@ -254,3 +288,26 @@ declare type Foo = { readonly b: string; }; declare function f10(foo: Foo): void; +declare type Func = (...args: any[]) => T; +declare type Spec = { + [P in keyof T]: Func | Spec; +}; +/** + * Given a spec object recursively mapping properties to functions, creates a function + * producing an object of the same structure, by mapping each property to the result + * of calling its associated function with the supplied arguments. + */ +declare function applySpec(obj: Spec): (...args: any[]) => T; +declare var g1: (...args: any[]) => { + sum: number; + nested: { + mul: string; + }; +}; +declare var g2: (...args: any[]) => { + foo: { + bar: { + baz: boolean; + }; + }; +}; diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.symbols b/tests/baselines/reference/isomorphicMappedTypeInference.symbols index 3e8a92e7691..92bcbb697ec 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.symbols +++ b/tests/baselines/reference/isomorphicMappedTypeInference.symbols @@ -393,3 +393,69 @@ function f10(foo: Foo) { >validateAndClone : Symbol(validateAndClone, Decl(isomorphicMappedTypeInference.ts, 107, 69)) >foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13)) } + +// Repro from #12606 + +type Func = (...args: any[]) => T; +>Func : Symbol(Func, Decl(isomorphicMappedTypeInference.ts, 119, 1)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 123, 10)) +>args : Symbol(args, Decl(isomorphicMappedTypeInference.ts, 123, 16)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 123, 10)) + +type Spec = { +>Spec : Symbol(Spec, Decl(isomorphicMappedTypeInference.ts, 123, 37)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 124, 10)) + + [P in keyof T]: Func | Spec ; +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 125, 5)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 124, 10)) +>Func : Symbol(Func, Decl(isomorphicMappedTypeInference.ts, 119, 1)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 124, 10)) +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 125, 5)) +>Spec : Symbol(Spec, Decl(isomorphicMappedTypeInference.ts, 123, 37)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 124, 10)) +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 125, 5)) + +}; + +/** + * Given a spec object recursively mapping properties to functions, creates a function + * producing an object of the same structure, by mapping each property to the result + * of calling its associated function with the supplied arguments. + */ +declare function applySpec(obj: Spec): (...args: any[]) => T; +>applySpec : Symbol(applySpec, Decl(isomorphicMappedTypeInference.ts, 126, 2)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 133, 27)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 133, 30)) +>Spec : Symbol(Spec, Decl(isomorphicMappedTypeInference.ts, 123, 37)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 133, 27)) +>args : Symbol(args, Decl(isomorphicMappedTypeInference.ts, 133, 46)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 133, 27)) + +// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } } +var g1 = applySpec({ +>g1 : Symbol(g1, Decl(isomorphicMappedTypeInference.ts, 136, 3)) +>applySpec : Symbol(applySpec, Decl(isomorphicMappedTypeInference.ts, 126, 2)) + + sum: (a: any) => 3, +>sum : Symbol(sum, Decl(isomorphicMappedTypeInference.ts, 136, 20)) +>a : Symbol(a, Decl(isomorphicMappedTypeInference.ts, 137, 10)) + + nested: { +>nested : Symbol(nested, Decl(isomorphicMappedTypeInference.ts, 137, 23)) + + mul: (b: any) => "n" +>mul : Symbol(mul, Decl(isomorphicMappedTypeInference.ts, 138, 13)) +>b : Symbol(b, Decl(isomorphicMappedTypeInference.ts, 139, 14)) + } +}); + +// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } } +var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } }); +>g2 : Symbol(g2, Decl(isomorphicMappedTypeInference.ts, 144, 3)) +>applySpec : Symbol(applySpec, Decl(isomorphicMappedTypeInference.ts, 126, 2)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 144, 20)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 144, 27)) +>baz : Symbol(baz, Decl(isomorphicMappedTypeInference.ts, 144, 34)) +>x : Symbol(x, Decl(isomorphicMappedTypeInference.ts, 144, 41)) + diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.types b/tests/baselines/reference/isomorphicMappedTypeInference.types index eee2d6cbe7d..b4d1383071b 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.types +++ b/tests/baselines/reference/isomorphicMappedTypeInference.types @@ -467,3 +467,82 @@ function f10(foo: Foo) { >validateAndClone : (obj: { readonly [P in keyof T]?: T[P] | undefined; }) => T >foo : Foo } + +// Repro from #12606 + +type Func = (...args: any[]) => T; +>Func : Func +>T : T +>args : any[] +>T : T + +type Spec = { +>Spec : Spec +>T : T + + [P in keyof T]: Func | Spec ; +>P : P +>T : T +>Func : Func +>T : T +>P : P +>Spec : Spec +>T : T +>P : P + +}; + +/** + * Given a spec object recursively mapping properties to functions, creates a function + * producing an object of the same structure, by mapping each property to the result + * of calling its associated function with the supplied arguments. + */ +declare function applySpec(obj: Spec): (...args: any[]) => T; +>applySpec : (obj: Spec) => (...args: any[]) => T +>T : T +>obj : Spec +>Spec : Spec +>T : T +>args : any[] +>T : T + +// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } } +var g1 = applySpec({ +>g1 : (...args: any[]) => { sum: number; nested: { mul: string; }; } +>applySpec({ sum: (a: any) => 3, nested: { mul: (b: any) => "n" }}) : (...args: any[]) => { sum: number; nested: { mul: string; }; } +>applySpec : (obj: Spec) => (...args: any[]) => T +>{ sum: (a: any) => 3, nested: { mul: (b: any) => "n" }} : { sum: (a: any) => number; nested: { mul: (b: any) => string; }; } + + sum: (a: any) => 3, +>sum : (a: any) => number +>(a: any) => 3 : (a: any) => number +>a : any +>3 : 3 + + nested: { +>nested : { mul: (b: any) => string; } +>{ mul: (b: any) => "n" } : { mul: (b: any) => string; } + + mul: (b: any) => "n" +>mul : (b: any) => string +>(b: any) => "n" : (b: any) => string +>b : any +>"n" : "n" + } +}); + +// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } } +var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } }); +>g2 : (...args: any[]) => { foo: { bar: { baz: boolean; }; }; } +>applySpec({ foo: { bar: { baz: (x: any) => true } } }) : (...args: any[]) => { foo: { bar: { baz: boolean; }; }; } +>applySpec : (obj: Spec) => (...args: any[]) => T +>{ foo: { bar: { baz: (x: any) => true } } } : { foo: { bar: { baz: (x: any) => boolean; }; }; } +>foo : { bar: { baz: (x: any) => boolean; }; } +>{ bar: { baz: (x: any) => true } } : { bar: { baz: (x: any) => boolean; }; } +>bar : { baz: (x: any) => boolean; } +>{ baz: (x: any) => true } : { baz: (x: any) => boolean; } +>baz : (x: any) => boolean +>(x: any) => true : (x: any) => boolean +>x : any +>true : true + diff --git a/tests/baselines/reference/keyofAndIndexedAccess.js b/tests/baselines/reference/keyofAndIndexedAccess.js index 8d8f125f39e..0e630be9a43 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.js +++ b/tests/baselines/reference/keyofAndIndexedAccess.js @@ -250,7 +250,48 @@ class OtherPerson { return getProperty(this, "parts") } } - + +// Modified repro from #12544 + +function path(obj: T, key1: K1): T[K1]; +function path(obj: T, key1: K1, key2: K2): T[K1][K2]; +function path(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; +function path(obj: any, ...keys: (string | number)[]): any; +function path(obj: any, ...keys: (string | number)[]): any { + let result = obj; + for (let k of keys) { + result = result[k]; + } + return result; +} + +type Thing = { + a: { x: number, y: string }, + b: boolean +}; + + +function f1(thing: Thing) { + let x1 = path(thing, 'a'); // { x: number, y: string } + let x2 = path(thing, 'a', 'y'); // string + let x3 = path(thing, 'b'); // boolean + let x4 = path(thing, ...['a', 'x']); // any +} + +// Repro from comment in #12114 + +const assignTo2 = (object: T, key1: K1, key2: K2) => + (value: T[K1][K2]) => object[key1][key2] = value; + +// Modified repro from #12573 + +declare function one(handler: (t: T) => void): T +var empty = one(() => {}) // inferred as {}, expected + +type Handlers = { [K in keyof T]: (t: T[K]) => void } +declare function on(handlerHash: Handlers): T +var hashOfEmpty1 = on({ test: () => {} }); // {} +var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean } //// [keyofAndIndexedAccess.js] var __extends = (this && this.__extends) || function (d, b) { @@ -430,6 +471,31 @@ var OtherPerson = (function () { }; return OtherPerson; }()); +function path(obj) { + var keys = []; + for (var _i = 1; _i < arguments.length; _i++) { + keys[_i - 1] = arguments[_i]; + } + var result = obj; + for (var _a = 0, keys_1 = keys; _a < keys_1.length; _a++) { + var k = keys_1[_a]; + result = result[k]; + } + return result; +} +function f1(thing) { + var x1 = path(thing, 'a'); // { x: number, y: string } + var x2 = path(thing, 'a', 'y'); // string + var x3 = path(thing, 'b'); // boolean + var x4 = path.apply(void 0, [thing].concat(['a', 'x'])); // any +} +// Repro from comment in #12114 +var assignTo2 = function (object, key1, key2) { + return function (value) { return object[key1][key2] = value; }; +}; +var empty = one(function () { }); // inferred as {}, expected +var hashOfEmpty1 = on({ test: function () { } }); // {} +var hashOfEmpty2 = on({ test: function (x) { } }); // { test: boolean } //// [keyofAndIndexedAccess.d.ts] @@ -551,3 +617,26 @@ declare class OtherPerson { constructor(parts: number); getParts(): number; } +declare function path(obj: T, key1: K1): T[K1]; +declare function path(obj: T, key1: K1, key2: K2): T[K1][K2]; +declare function path(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; +declare function path(obj: any, ...keys: (string | number)[]): any; +declare type Thing = { + a: { + x: number; + y: string; + }; + b: boolean; +}; +declare function f1(thing: Thing): void; +declare const assignTo2: (object: T, key1: K1, key2: K2) => (value: T[K1][K2]) => T[K1][K2]; +declare function one(handler: (t: T) => void): T; +declare var empty: {}; +declare type Handlers = { + [K in keyof T]: (t: T[K]) => void; +}; +declare function on(handlerHash: Handlers): T; +declare var hashOfEmpty1: {}; +declare var hashOfEmpty2: { + test: boolean; +}; diff --git a/tests/baselines/reference/keyofAndIndexedAccess.symbols b/tests/baselines/reference/keyofAndIndexedAccess.symbols index 2371bf419c8..e67db316dad 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.symbols +++ b/tests/baselines/reference/keyofAndIndexedAccess.symbols @@ -848,3 +848,196 @@ class OtherPerson { } } +// Modified repro from #12544 + +function path(obj: T, key1: K1): T[K1]; +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 254, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 254, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 254, 14)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 254, 37)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 254, 14)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 254, 44)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 254, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 254, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 254, 16)) + +function path(obj: T, key1: K1, key2: K2): T[K1][K2]; +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 255, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 255, 36)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 255, 16)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 255, 61)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 255, 68)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 255, 16)) +>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 255, 78)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 255, 36)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 255, 16)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 255, 36)) + +function path(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 256, 36)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16)) +>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 256, 60)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 256, 36)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 256, 89)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 256, 96)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16)) +>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 256, 106)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 256, 36)) +>key3 : Symbol(key3, Decl(keyofAndIndexedAccess.ts, 256, 116)) +>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 256, 60)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 256, 36)) +>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 256, 60)) + +function path(obj: any, ...keys: (string | number)[]): any; +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 257, 14)) +>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 257, 23)) + +function path(obj: any, ...keys: (string | number)[]): any { +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 258, 14)) +>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 258, 23)) + + let result = obj; +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 259, 7)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 258, 14)) + + for (let k of keys) { +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 260, 12)) +>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 258, 23)) + + result = result[k]; +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 259, 7)) +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 259, 7)) +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 260, 12)) + } + return result; +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 259, 7)) +} + +type Thing = { +>Thing : Symbol(Thing, Decl(keyofAndIndexedAccess.ts, 264, 1)) + + a: { x: number, y: string }, +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 266, 14)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 267, 8)) +>y : Symbol(y, Decl(keyofAndIndexedAccess.ts, 267, 19)) + + b: boolean +>b : Symbol(b, Decl(keyofAndIndexedAccess.ts, 267, 32)) + +}; + + +function f1(thing: Thing) { +>f1 : Symbol(f1, Decl(keyofAndIndexedAccess.ts, 269, 2)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12)) +>Thing : Symbol(Thing, Decl(keyofAndIndexedAccess.ts, 264, 1)) + + let x1 = path(thing, 'a'); // { x: number, y: string } +>x1 : Symbol(x1, Decl(keyofAndIndexedAccess.ts, 273, 7)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12)) + + let x2 = path(thing, 'a', 'y'); // string +>x2 : Symbol(x2, Decl(keyofAndIndexedAccess.ts, 274, 7)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12)) + + let x3 = path(thing, 'b'); // boolean +>x3 : Symbol(x3, Decl(keyofAndIndexedAccess.ts, 275, 7)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12)) + + let x4 = path(thing, ...['a', 'x']); // any +>x4 : Symbol(x4, Decl(keyofAndIndexedAccess.ts, 276, 7)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12)) +} + +// Repro from comment in #12114 + +const assignTo2 = (object: T, key1: K1, key2: K2) => +>assignTo2 : Symbol(assignTo2, Decl(keyofAndIndexedAccess.ts, 281, 5)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 281, 21)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 281, 41)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 281, 21)) +>object : Symbol(object, Decl(keyofAndIndexedAccess.ts, 281, 66)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 281, 76)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 281, 21)) +>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 281, 86)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 281, 41)) + + (value: T[K1][K2]) => object[key1][key2] = value; +>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 282, 5)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 281, 21)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 281, 41)) +>object : Symbol(object, Decl(keyofAndIndexedAccess.ts, 281, 66)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 281, 76)) +>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 281, 86)) +>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 282, 5)) + +// Modified repro from #12573 + +declare function one(handler: (t: T) => void): T +>one : Symbol(one, Decl(keyofAndIndexedAccess.ts, 282, 53)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 21)) +>handler : Symbol(handler, Decl(keyofAndIndexedAccess.ts, 286, 24)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 286, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 21)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 21)) + +var empty = one(() => {}) // inferred as {}, expected +>empty : Symbol(empty, Decl(keyofAndIndexedAccess.ts, 287, 3)) +>one : Symbol(one, Decl(keyofAndIndexedAccess.ts, 282, 53)) + +type Handlers = { [K in keyof T]: (t: T[K]) => void } +>Handlers : Symbol(Handlers, Decl(keyofAndIndexedAccess.ts, 287, 25)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 289, 14)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 289, 22)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 289, 14)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 289, 38)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 289, 14)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 289, 22)) + +declare function on(handlerHash: Handlers): T +>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 289, 56)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 290, 20)) +>handlerHash : Symbol(handlerHash, Decl(keyofAndIndexedAccess.ts, 290, 23)) +>Handlers : Symbol(Handlers, Decl(keyofAndIndexedAccess.ts, 287, 25)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 290, 20)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 290, 20)) + +var hashOfEmpty1 = on({ test: () => {} }); // {} +>hashOfEmpty1 : Symbol(hashOfEmpty1, Decl(keyofAndIndexedAccess.ts, 291, 3)) +>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 289, 56)) +>test : Symbol(test, Decl(keyofAndIndexedAccess.ts, 291, 23)) + +var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean } +>hashOfEmpty2 : Symbol(hashOfEmpty2, Decl(keyofAndIndexedAccess.ts, 292, 3)) +>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 289, 56)) +>test : Symbol(test, Decl(keyofAndIndexedAccess.ts, 292, 23)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 292, 31)) + diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index fa54c614f07..9e1e7d4b4d1 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -982,3 +982,223 @@ class OtherPerson { } } +// Modified repro from #12544 + +function path(obj: T, key1: K1): T[K1]; +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>T : T +>K1 : K1 +>T : T +>obj : T +>T : T +>key1 : K1 +>K1 : K1 +>T : T +>K1 : K1 + +function path(obj: T, key1: K1, key2: K2): T[K1][K2]; +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>T : T +>K1 : K1 +>T : T +>K2 : K2 +>T : T +>K1 : K1 +>obj : T +>T : T +>key1 : K1 +>K1 : K1 +>key2 : K2 +>K2 : K2 +>T : T +>K1 : K1 +>K2 : K2 + +function path(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>T : T +>K1 : K1 +>T : T +>K2 : K2 +>T : T +>K1 : K1 +>K3 : K3 +>T : T +>K1 : K1 +>K2 : K2 +>obj : T +>T : T +>key1 : K1 +>K1 : K1 +>key2 : K2 +>K2 : K2 +>key3 : K3 +>K3 : K3 +>T : T +>K1 : K1 +>K2 : K2 +>K3 : K3 + +function path(obj: any, ...keys: (string | number)[]): any; +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>obj : any +>keys : (string | number)[] + +function path(obj: any, ...keys: (string | number)[]): any { +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>obj : any +>keys : (string | number)[] + + let result = obj; +>result : any +>obj : any + + for (let k of keys) { +>k : string | number +>keys : (string | number)[] + + result = result[k]; +>result = result[k] : any +>result : any +>result[k] : any +>result : any +>k : string | number + } + return result; +>result : any +} + +type Thing = { +>Thing : Thing + + a: { x: number, y: string }, +>a : { x: number; y: string; } +>x : number +>y : string + + b: boolean +>b : boolean + +}; + + +function f1(thing: Thing) { +>f1 : (thing: Thing) => void +>thing : Thing +>Thing : Thing + + let x1 = path(thing, 'a'); // { x: number, y: string } +>x1 : { x: number; y: string; } +>path(thing, 'a') : { x: number; y: string; } +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>thing : Thing +>'a' : "a" + + let x2 = path(thing, 'a', 'y'); // string +>x2 : string +>path(thing, 'a', 'y') : string +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>thing : Thing +>'a' : "a" +>'y' : "y" + + let x3 = path(thing, 'b'); // boolean +>x3 : boolean +>path(thing, 'b') : boolean +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>thing : Thing +>'b' : "b" + + let x4 = path(thing, ...['a', 'x']); // any +>x4 : any +>path(thing, ...['a', 'x']) : any +>path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } +>thing : Thing +>...['a', 'x'] : string +>['a', 'x'] : string[] +>'a' : "a" +>'x' : "x" +} + +// Repro from comment in #12114 + +const assignTo2 = (object: T, key1: K1, key2: K2) => +>assignTo2 : (object: T, key1: K1, key2: K2) => (value: T[K1][K2]) => T[K1][K2] +>(object: T, key1: K1, key2: K2) => (value: T[K1][K2]) => object[key1][key2] = value : (object: T, key1: K1, key2: K2) => (value: T[K1][K2]) => T[K1][K2] +>T : T +>K1 : K1 +>T : T +>K2 : K2 +>T : T +>K1 : K1 +>object : T +>T : T +>key1 : K1 +>K1 : K1 +>key2 : K2 +>K2 : K2 + + (value: T[K1][K2]) => object[key1][key2] = value; +>(value: T[K1][K2]) => object[key1][key2] = value : (value: T[K1][K2]) => T[K1][K2] +>value : T[K1][K2] +>T : T +>K1 : K1 +>K2 : K2 +>object[key1][key2] = value : T[K1][K2] +>object[key1][key2] : T[K1][K2] +>object[key1] : T[K1] +>object : T +>key1 : K1 +>key2 : K2 +>value : T[K1][K2] + +// Modified repro from #12573 + +declare function one(handler: (t: T) => void): T +>one : (handler: (t: T) => void) => T +>T : T +>handler : (t: T) => void +>t : T +>T : T +>T : T + +var empty = one(() => {}) // inferred as {}, expected +>empty : {} +>one(() => {}) : {} +>one : (handler: (t: T) => void) => T +>() => {} : () => void + +type Handlers = { [K in keyof T]: (t: T[K]) => void } +>Handlers : Handlers +>T : T +>K : K +>T : T +>t : T[K] +>T : T +>K : K + +declare function on(handlerHash: Handlers): T +>on : (handlerHash: Handlers) => T +>T : T +>handlerHash : Handlers +>Handlers : Handlers +>T : T +>T : T + +var hashOfEmpty1 = on({ test: () => {} }); // {} +>hashOfEmpty1 : {} +>on({ test: () => {} }) : {} +>on : (handlerHash: Handlers) => T +>{ test: () => {} } : { test: () => void; } +>test : () => void +>() => {} : () => void + +var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean } +>hashOfEmpty2 : { test: boolean; } +>on({ test: (x: boolean) => {} }) : { test: boolean; } +>on : (handlerHash: Handlers) => T +>{ test: (x: boolean) => {} } : { test: (x: boolean) => void; } +>test : (x: boolean) => void +>(x: boolean) => {} : (x: boolean) => void +>x : boolean +