Use string/number signature to get contextual type

Fixes #26587
This commit is contained in:
Sheetal Nandi
2018-10-10 14:51:17 -07:00
parent 4d504f9b30
commit c0729a22fd
13 changed files with 76 additions and 106 deletions

View File

@@ -16708,6 +16708,8 @@ namespace ts {
return restType;
}
}
return isNumericLiteralName(name) && getIndexTypeOfContextualType(type, IndexKind.Number) ||
getIndexTypeOfContextualType(type, IndexKind.String);
}
return undefined;
}, /*noReductions*/ true);

View File

@@ -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

View File

@@ -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))

View File

@@ -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

View File

@@ -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<State> {
[prop: string]: (state: State) => State;
}
interface Options<State, Actions> {
state?: State;
view?: (state: State, actions: Actions) => any;
actions: string | Actions;
}
declare function app<State, Actions extends ActionsObject<State>>(obj: Options<State, Actions>): 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<T extends Bar>(x: string | T): T;
const y = foo({
bar(x) { // Should be typed number => void
}
});
interface Options2<State, Actions> {
state?: State;
view?: (state: State, actions: Actions) => any;
actions?: Actions;
}
declare function app2<State, Actions extends ActionsObject<State>>(obj: Options2<State, Actions>): void;
app2({
state: 100,
actions: {
foo: s => s // Should be typed number => number
},
view: (s, a) => undefined as any,
});
type ActionsArray<State> = ((state: State) => State)[];
declare function app3<State, Actions extends ActionsArray<State>>(obj: Options<State, Actions>): 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<State> {
[prop: string]: ((state: State) => State) | State;
}
declare function App4<State, Actions extends ActionsObjectOr<State>>(props: Options<State, Actions>["actions"] & { state: State }): JSX.Element;
const a = <App4 state={100} foo={s => s} />; // TODO: should be number => number, but JSX resolution is missing an inferential pass
~
!!! error TS7006: Parameter 's' implicitly has an 'any' type.

View File

@@ -183,8 +183,8 @@ const a = <App4 state={100} foo={s => s} />; // TODO: should be number => number
>App4 : <State, Actions extends ActionsObjectOr<State>>(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

View File

@@ -543,7 +543,7 @@ function multipleGenericFuse<X extends L | number, Y extends R | number>(xy: X |
case 'function': return [xy, 1];
>'function' : "function"
>[xy, 1] : [X, number]
>[xy, 1] : [X, 1]
>xy : X
>1 : 1

View File

@@ -35,7 +35,7 @@ export class MyComponent {
<MyComponent bar={true} />;
><MyComponent bar={true} /> : JSX.Element
>MyComponent : typeof MyComponent
>bar : boolean
>bar : true
>true : true
// Should be ok

View File

@@ -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" };

View File

@@ -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))

View File

@@ -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"

View File

@@ -0,0 +1,4 @@
interface I { x: number; }
interface Idx { [index: string]: U; }
type U = Idx | I | "lit";
const u: U = { x: "lit" };

View File

@@ -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