From c0729a22fd364b42f26ef550b56c8132fca079f4 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 10 Oct 2018 14:51:17 -0700 Subject: [PATCH] Use string/number signature to get contextual type Fixes #26587 --- src/compiler/checker.ts | 2 + ...textualTypeWithUnionTypeIndexSignatures.js | 8 +- ...alTypeWithUnionTypeIndexSignatures.symbols | 4 +- ...tualTypeWithUnionTypeIndexSignatures.types | 24 +++--- ...ntextualTypingOfOptionalMembers.errors.txt | 80 ------------------- .../contextualTypingOfOptionalMembers.types | 8 +- .../reference/narrowingByTypeofInSwitch.types | 2 +- .../reference/tsxAttributeResolution10.types | 2 +- .../unionTypeWithIndexedLiteralType.js | 8 ++ .../unionTypeWithIndexedLiteralType.symbols | 20 +++++ .../unionTypeWithIndexedLiteralType.types | 16 ++++ .../unionTypeWithIndexedLiteralType.ts | 4 + ...textualTypeWithUnionTypeIndexSignatures.ts | 4 +- 13 files changed, 76 insertions(+), 106 deletions(-) delete mode 100644 tests/baselines/reference/contextualTypingOfOptionalMembers.errors.txt create mode 100644 tests/baselines/reference/unionTypeWithIndexedLiteralType.js create mode 100644 tests/baselines/reference/unionTypeWithIndexedLiteralType.symbols create mode 100644 tests/baselines/reference/unionTypeWithIndexedLiteralType.types create mode 100644 tests/cases/compiler/unionTypeWithIndexedLiteralType.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bc93cce86b89f..dd8886b28544a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16708,6 +16708,8 @@ namespace ts { return restType; } } + return isNumericLiteralName(name) && getIndexTypeOfContextualType(type, IndexKind.Number) || + getIndexTypeOfContextualType(type, IndexKind.String); } return undefined; }, /*noReductions*/ true); diff --git a/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.js b/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.js index 2c07f46142436..0ddadeab96cea 100644 --- a/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.js +++ b/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.js @@ -39,7 +39,7 @@ interface IWithNumberIndexSignature2 { // If S is not empty, U has a string index signature of a union type of // the types of the string index signatures from each type in S. var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { z: a => a }; // a should be number -var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: a => a }; // a should be any +var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: a => a }; // a should be number (because of index signature of IWithStringIndexSignature1) var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: "hello" }; var x2: IWithStringIndexSignature1 | IWithStringIndexSignature2 = { z: a => a.toString() }; // a should be number var x2: IWithStringIndexSignature1 | IWithStringIndexSignature2 = { z: a => a }; // a should be number @@ -49,7 +49,7 @@ var x2: IWithStringIndexSignature1 | IWithStringIndexSignature2 = { z: a => a }; // If S is not empty, U has a numeric index signature of a union type of // the types of the numeric index signatures from each type in S. var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 1: a => a }; // a should be number -var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: a => a }; // a should be any +var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: a => a }; // a should be number (because of index signature of IWithNumberIndexSignature1) var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: "hello" }; var x4: IWithNumberIndexSignature1 | IWithNumberIndexSignature2 = { 1: a => a.toString() }; // a should be number var x4: IWithNumberIndexSignature1 | IWithNumberIndexSignature2 = { 1: a => a }; // a should be number @@ -66,7 +66,7 @@ var x4: IWithNumberIndexSignature1 | IWithNumberIndexSignature2 = { 1: a => a }; // If S is not empty, U has a string index signature of a union type of // the types of the string index signatures from each type in S. var x = { z: function (a) { return a; } }; // a should be number -var x = { foo: function (a) { return a; } }; // a should be any +var x = { foo: function (a) { return a; } }; // a should be number (because of index signature of IWithStringIndexSignature1) var x = { foo: "hello" }; var x2 = { z: function (a) { return a.toString(); } }; // a should be number var x2 = { z: function (a) { return a; } }; // a should be number @@ -74,7 +74,7 @@ var x2 = { z: function (a) { return a; } }; // a should be number // If S is not empty, U has a numeric index signature of a union type of // the types of the numeric index signatures from each type in S. var x3 = { 1: function (a) { return a; } }; // a should be number -var x3 = { 0: function (a) { return a; } }; // a should be any +var x3 = { 0: function (a) { return a; } }; // a should be number (because of index signature of IWithNumberIndexSignature1) var x3 = { 0: "hello" }; var x4 = { 1: function (a) { return a.toString(); } }; // a should be number var x4 = { 1: function (a) { return a; } }; // a should be number diff --git a/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.symbols b/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.symbols index 69e9e9e52ea1b..d2959a005e27c 100644 --- a/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.symbols +++ b/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.symbols @@ -74,7 +74,7 @@ var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { z: a => a }; >a : Symbol(a, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 39, 70)) >a : Symbol(a, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 39, 70)) -var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: a => a }; // a should be any +var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: a => a }; // a should be number (because of index signature of IWithStringIndexSignature1) >x : Symbol(x, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 39, 3), Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 40, 3), Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 41, 3)) >IWithNoStringIndexSignature : Symbol(IWithNoStringIndexSignature, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 7, 1)) >IWithStringIndexSignature1 : Symbol(IWithStringIndexSignature1, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 14, 1)) @@ -118,7 +118,7 @@ var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 1: a => a } >a : Symbol(a, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 49, 71)) >a : Symbol(a, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 49, 71)) -var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: a => a }; // a should be any +var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: a => a }; // a should be number (because of index signature of IWithNumberIndexSignature1) >x3 : Symbol(x3, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 49, 3), Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 50, 3), Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 51, 3)) >IWithNoNumberIndexSignature : Symbol(IWithNoNumberIndexSignature, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 11, 1)) >IWithNumberIndexSignature1 : Symbol(IWithNumberIndexSignature1, Decl(contextualTypeWithUnionTypeIndexSignatures.ts, 20, 1)) diff --git a/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.types b/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.types index 985467ae7eaed..6c4638ad75a34 100644 --- a/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.types +++ b/tests/baselines/reference/contextualTypeWithUnionTypeIndexSignatures.types @@ -54,13 +54,13 @@ var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { z: a => a }; >a : number >a : number -var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: a => a }; // a should be any +var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: a => a }; // a should be number (because of index signature of IWithStringIndexSignature1) >x : IWithNoStringIndexSignature | IWithStringIndexSignature1 ->{ foo: a => a } : { foo: (a: any) => any; } ->foo : (a: any) => any ->a => a : (a: any) => any ->a : any ->a : any +>{ foo: a => a } : { foo: (a: number) => number; } +>foo : (a: number) => number +>a => a : (a: number) => number +>a : number +>a : number var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: "hello" }; >x : IWithNoStringIndexSignature | IWithStringIndexSignature1 @@ -99,13 +99,13 @@ var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 1: a => a } >a : number >a : number -var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: a => a }; // a should be any +var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: a => a }; // a should be number (because of index signature of IWithNumberIndexSignature1) >x3 : IWithNoNumberIndexSignature | IWithNumberIndexSignature1 ->{ 0: a => a } : { 0: (a: any) => any; } ->0 : (a: any) => any ->a => a : (a: any) => any ->a : any ->a : any +>{ 0: a => a } : { 0: (a: number) => number; } +>0 : (a: number) => number +>a => a : (a: number) => number +>a : number +>a : number var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: "hello" }; >x3 : IWithNoNumberIndexSignature | IWithNumberIndexSignature1 diff --git a/tests/baselines/reference/contextualTypingOfOptionalMembers.errors.txt b/tests/baselines/reference/contextualTypingOfOptionalMembers.errors.txt deleted file mode 100644 index 02c94400e2167..0000000000000 --- a/tests/baselines/reference/contextualTypingOfOptionalMembers.errors.txt +++ /dev/null @@ -1,80 +0,0 @@ -tests/cases/compiler/index.tsx(73,34): error TS7006: Parameter 's' implicitly has an 'any' type. - - -==== tests/cases/compiler/index.tsx (1 errors) ==== - interface ActionsObject { - [prop: string]: (state: State) => State; - } - - interface Options { - state?: State; - view?: (state: State, actions: Actions) => any; - actions: string | Actions; - } - - declare function app>(obj: Options): void; - - app({ - state: 100, - actions: { - foo: s => s // Should be typed number => number - }, - view: (s, a) => undefined as any, - }); - - - interface Bar { - bar: (a: number) => void; - } - - declare function foo(x: string | T): T; - - const y = foo({ - bar(x) { // Should be typed number => void - } - }); - - interface Options2 { - state?: State; - view?: (state: State, actions: Actions) => any; - actions?: Actions; - } - - declare function app2>(obj: Options2): void; - - app2({ - state: 100, - actions: { - foo: s => s // Should be typed number => number - }, - view: (s, a) => undefined as any, - }); - - - type ActionsArray = ((state: State) => State)[]; - - declare function app3>(obj: Options): void; - - app3({ - state: 100, - actions: [ - s => s // Should be typed number => number - ], - view: (s, a) => undefined as any, - }); - - namespace JSX { - export interface Element {} - export interface IntrinsicElements {} - } - - interface ActionsObjectOr { - [prop: string]: ((state: State) => State) | State; - } - - declare function App4>(props: Options["actions"] & { state: State }): JSX.Element; - - const a = s} />; // TODO: should be number => number, but JSX resolution is missing an inferential pass - ~ -!!! error TS7006: Parameter 's' implicitly has an 'any' type. - \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypingOfOptionalMembers.types b/tests/baselines/reference/contextualTypingOfOptionalMembers.types index 389ad15a579cf..f4a9e23190d9d 100644 --- a/tests/baselines/reference/contextualTypingOfOptionalMembers.types +++ b/tests/baselines/reference/contextualTypingOfOptionalMembers.types @@ -183,8 +183,8 @@ const a = s} />; // TODO: should be number => number >App4 : >(props: (string & { state: State; }) | (Actions & { state: State; })) => JSX.Element >state : number >100 : 100 ->foo : (s: any) => any ->s => s : (s: any) => any ->s : any ->s : any +>foo : (s: number) => number +>s => s : (s: number) => number +>s : number +>s : number diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.types b/tests/baselines/reference/narrowingByTypeofInSwitch.types index 000eea75f7908..342aeb670ec15 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.types +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.types @@ -543,7 +543,7 @@ function multipleGenericFuse(xy: X | case 'function': return [xy, 1]; >'function' : "function" ->[xy, 1] : [X, number] +>[xy, 1] : [X, 1] >xy : X >1 : 1 diff --git a/tests/baselines/reference/tsxAttributeResolution10.types b/tests/baselines/reference/tsxAttributeResolution10.types index 4acabaffa4d55..ddc834fe4c7bb 100644 --- a/tests/baselines/reference/tsxAttributeResolution10.types +++ b/tests/baselines/reference/tsxAttributeResolution10.types @@ -35,7 +35,7 @@ export class MyComponent { ; > : JSX.Element >MyComponent : typeof MyComponent ->bar : boolean +>bar : true >true : true // Should be ok diff --git a/tests/baselines/reference/unionTypeWithIndexedLiteralType.js b/tests/baselines/reference/unionTypeWithIndexedLiteralType.js new file mode 100644 index 0000000000000..8ed8d32b3f58f --- /dev/null +++ b/tests/baselines/reference/unionTypeWithIndexedLiteralType.js @@ -0,0 +1,8 @@ +//// [unionTypeWithIndexedLiteralType.ts] +interface I { x: number; } +interface Idx { [index: string]: U; } +type U = Idx | I | "lit"; +const u: U = { x: "lit" }; + +//// [unionTypeWithIndexedLiteralType.js] +var u = { x: "lit" }; diff --git a/tests/baselines/reference/unionTypeWithIndexedLiteralType.symbols b/tests/baselines/reference/unionTypeWithIndexedLiteralType.symbols new file mode 100644 index 0000000000000..bf9502ee5a563 --- /dev/null +++ b/tests/baselines/reference/unionTypeWithIndexedLiteralType.symbols @@ -0,0 +1,20 @@ +=== tests/cases/compiler/unionTypeWithIndexedLiteralType.ts === +interface I { x: number; } +>I : Symbol(I, Decl(unionTypeWithIndexedLiteralType.ts, 0, 0)) +>x : Symbol(I.x, Decl(unionTypeWithIndexedLiteralType.ts, 0, 13)) + +interface Idx { [index: string]: U; } +>Idx : Symbol(Idx, Decl(unionTypeWithIndexedLiteralType.ts, 0, 26)) +>index : Symbol(index, Decl(unionTypeWithIndexedLiteralType.ts, 1, 17)) +>U : Symbol(U, Decl(unionTypeWithIndexedLiteralType.ts, 1, 37)) + +type U = Idx | I | "lit"; +>U : Symbol(U, Decl(unionTypeWithIndexedLiteralType.ts, 1, 37)) +>Idx : Symbol(Idx, Decl(unionTypeWithIndexedLiteralType.ts, 0, 26)) +>I : Symbol(I, Decl(unionTypeWithIndexedLiteralType.ts, 0, 0)) + +const u: U = { x: "lit" }; +>u : Symbol(u, Decl(unionTypeWithIndexedLiteralType.ts, 3, 5)) +>U : Symbol(U, Decl(unionTypeWithIndexedLiteralType.ts, 1, 37)) +>x : Symbol(x, Decl(unionTypeWithIndexedLiteralType.ts, 3, 14)) + diff --git a/tests/baselines/reference/unionTypeWithIndexedLiteralType.types b/tests/baselines/reference/unionTypeWithIndexedLiteralType.types new file mode 100644 index 0000000000000..47d1d6832e183 --- /dev/null +++ b/tests/baselines/reference/unionTypeWithIndexedLiteralType.types @@ -0,0 +1,16 @@ +=== tests/cases/compiler/unionTypeWithIndexedLiteralType.ts === +interface I { x: number; } +>x : number + +interface Idx { [index: string]: U; } +>index : string + +type U = Idx | I | "lit"; +>U : U + +const u: U = { x: "lit" }; +>u : U +>{ x: "lit" } : { x: "lit"; } +>x : "lit" +>"lit" : "lit" + diff --git a/tests/cases/compiler/unionTypeWithIndexedLiteralType.ts b/tests/cases/compiler/unionTypeWithIndexedLiteralType.ts new file mode 100644 index 0000000000000..c594c6d1c9d85 --- /dev/null +++ b/tests/cases/compiler/unionTypeWithIndexedLiteralType.ts @@ -0,0 +1,4 @@ +interface I { x: number; } +interface Idx { [index: string]: U; } +type U = Idx | I | "lit"; +const u: U = { x: "lit" }; \ No newline at end of file diff --git a/tests/cases/conformance/types/union/contextualTypeWithUnionTypeIndexSignatures.ts b/tests/cases/conformance/types/union/contextualTypeWithUnionTypeIndexSignatures.ts index 9132c61f4fe1f..a7408672118fb 100644 --- a/tests/cases/conformance/types/union/contextualTypeWithUnionTypeIndexSignatures.ts +++ b/tests/cases/conformance/types/union/contextualTypeWithUnionTypeIndexSignatures.ts @@ -38,7 +38,7 @@ interface IWithNumberIndexSignature2 { // If S is not empty, U has a string index signature of a union type of // the types of the string index signatures from each type in S. var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { z: a => a }; // a should be number -var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: a => a }; // a should be any +var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: a => a }; // a should be number (because of index signature of IWithStringIndexSignature1) var x: IWithNoStringIndexSignature | IWithStringIndexSignature1 = { foo: "hello" }; var x2: IWithStringIndexSignature1 | IWithStringIndexSignature2 = { z: a => a.toString() }; // a should be number var x2: IWithStringIndexSignature1 | IWithStringIndexSignature2 = { z: a => a }; // a should be number @@ -48,7 +48,7 @@ var x2: IWithStringIndexSignature1 | IWithStringIndexSignature2 = { z: a => a }; // If S is not empty, U has a numeric index signature of a union type of // the types of the numeric index signatures from each type in S. var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 1: a => a }; // a should be number -var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: a => a }; // a should be any +var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: a => a }; // a should be number (because of index signature of IWithNumberIndexSignature1) var x3: IWithNoNumberIndexSignature | IWithNumberIndexSignature1 = { 0: "hello" }; var x4: IWithNumberIndexSignature1 | IWithNumberIndexSignature2 = { 1: a => a.toString() }; // a should be number var x4: IWithNumberIndexSignature1 | IWithNumberIndexSignature2 = { 1: a => a }; // a should be number \ No newline at end of file