Make getContextualTypeOfApparentType mapType over unions (#17668)

* Instantiate contextual types while in an inferrential context

* Limit scope of instantiation to only when likely needed

* Still get aparent type

* Expand test

* Fix nit

* Handle JSX and array

* Tests for the JSX and Array cases

* After much deliberation and inspection, much simpler fix

After much deliberation and inspection, much simpler fix

Undo

Redo
This commit is contained in:
Wesley Wigham 2017-11-06 12:52:33 -08:00 committed by GitHub
parent 4f48bf80fe
commit 0593ba27d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 757 additions and 1 deletions

View File

@ -13691,7 +13691,7 @@ namespace ts {
// be "pushed" onto a node using the contextualType property.
function getApparentTypeOfContextualType(node: Expression): Type {
const type = getContextualType(node);
return type && getApparentType(type);
return type && mapType(type, getApparentType);
}
/**

View File

@ -0,0 +1,80 @@
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

@ -0,0 +1,103 @@
//// [index.tsx]
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
//// [index.jsx]
app({
state: 100,
actions: {
foo: function (s) { return s; } // Should be typed number => number
},
view: function (s, a) { return undefined; }
});
var y = foo({
bar: function (x) {
}
});
app2({
state: 100,
actions: {
foo: function (s) { return s; } // Should be typed number => number
},
view: function (s, a) { return undefined; }
});
app3({
state: 100,
actions: [
function (s) { return s; } // Should be typed number => number
],
view: function (s, a) { return undefined; }
});
var a = <App4 state={100} foo={function (s) { return s; }}/>; // TODO: should be number => number, but JSX resolution is missing an inferential pass

View File

@ -0,0 +1,235 @@
=== tests/cases/compiler/index.tsx ===
interface ActionsObject<State> {
>ActionsObject : Symbol(ActionsObject, Decl(index.tsx, 0, 0))
>State : Symbol(State, Decl(index.tsx, 0, 24))
[prop: string]: (state: State) => State;
>prop : Symbol(prop, Decl(index.tsx, 1, 5))
>state : Symbol(state, Decl(index.tsx, 1, 21))
>State : Symbol(State, Decl(index.tsx, 0, 24))
>State : Symbol(State, Decl(index.tsx, 0, 24))
}
interface Options<State, Actions> {
>Options : Symbol(Options, Decl(index.tsx, 2, 1))
>State : Symbol(State, Decl(index.tsx, 4, 18))
>Actions : Symbol(Actions, Decl(index.tsx, 4, 24))
state?: State;
>state : Symbol(Options.state, Decl(index.tsx, 4, 35))
>State : Symbol(State, Decl(index.tsx, 4, 18))
view?: (state: State, actions: Actions) => any;
>view : Symbol(Options.view, Decl(index.tsx, 5, 18))
>state : Symbol(state, Decl(index.tsx, 6, 12))
>State : Symbol(State, Decl(index.tsx, 4, 18))
>actions : Symbol(actions, Decl(index.tsx, 6, 25))
>Actions : Symbol(Actions, Decl(index.tsx, 4, 24))
actions: string | Actions;
>actions : Symbol(Options.actions, Decl(index.tsx, 6, 51))
>Actions : Symbol(Actions, Decl(index.tsx, 4, 24))
}
declare function app<State, Actions extends ActionsObject<State>>(obj: Options<State, Actions>): void;
>app : Symbol(app, Decl(index.tsx, 8, 1))
>State : Symbol(State, Decl(index.tsx, 10, 21))
>Actions : Symbol(Actions, Decl(index.tsx, 10, 27))
>ActionsObject : Symbol(ActionsObject, Decl(index.tsx, 0, 0))
>State : Symbol(State, Decl(index.tsx, 10, 21))
>obj : Symbol(obj, Decl(index.tsx, 10, 66))
>Options : Symbol(Options, Decl(index.tsx, 2, 1))
>State : Symbol(State, Decl(index.tsx, 10, 21))
>Actions : Symbol(Actions, Decl(index.tsx, 10, 27))
app({
>app : Symbol(app, Decl(index.tsx, 8, 1))
state: 100,
>state : Symbol(state, Decl(index.tsx, 12, 5))
actions: {
>actions : Symbol(actions, Decl(index.tsx, 13, 15))
foo: s => s // Should be typed number => number
>foo : Symbol(foo, Decl(index.tsx, 14, 14))
>s : Symbol(s, Decl(index.tsx, 15, 12))
>s : Symbol(s, Decl(index.tsx, 15, 12))
},
view: (s, a) => undefined as any,
>view : Symbol(view, Decl(index.tsx, 16, 6))
>s : Symbol(s, Decl(index.tsx, 17, 11))
>a : Symbol(a, Decl(index.tsx, 17, 13))
>undefined : Symbol(undefined)
});
interface Bar {
>Bar : Symbol(Bar, Decl(index.tsx, 18, 3))
bar: (a: number) => void;
>bar : Symbol(Bar.bar, Decl(index.tsx, 21, 15))
>a : Symbol(a, Decl(index.tsx, 22, 10))
}
declare function foo<T extends Bar>(x: string | T): T;
>foo : Symbol(foo, Decl(index.tsx, 23, 1))
>T : Symbol(T, Decl(index.tsx, 25, 21))
>Bar : Symbol(Bar, Decl(index.tsx, 18, 3))
>x : Symbol(x, Decl(index.tsx, 25, 36))
>T : Symbol(T, Decl(index.tsx, 25, 21))
>T : Symbol(T, Decl(index.tsx, 25, 21))
const y = foo({
>y : Symbol(y, Decl(index.tsx, 27, 5))
>foo : Symbol(foo, Decl(index.tsx, 23, 1))
bar(x) { // Should be typed number => void
>bar : Symbol(bar, Decl(index.tsx, 27, 15))
>x : Symbol(x, Decl(index.tsx, 28, 8))
}
});
interface Options2<State, Actions> {
>Options2 : Symbol(Options2, Decl(index.tsx, 30, 3))
>State : Symbol(State, Decl(index.tsx, 32, 19))
>Actions : Symbol(Actions, Decl(index.tsx, 32, 25))
state?: State;
>state : Symbol(Options2.state, Decl(index.tsx, 32, 36))
>State : Symbol(State, Decl(index.tsx, 32, 19))
view?: (state: State, actions: Actions) => any;
>view : Symbol(Options2.view, Decl(index.tsx, 33, 18))
>state : Symbol(state, Decl(index.tsx, 34, 12))
>State : Symbol(State, Decl(index.tsx, 32, 19))
>actions : Symbol(actions, Decl(index.tsx, 34, 25))
>Actions : Symbol(Actions, Decl(index.tsx, 32, 25))
actions?: Actions;
>actions : Symbol(Options2.actions, Decl(index.tsx, 34, 51))
>Actions : Symbol(Actions, Decl(index.tsx, 32, 25))
}
declare function app2<State, Actions extends ActionsObject<State>>(obj: Options2<State, Actions>): void;
>app2 : Symbol(app2, Decl(index.tsx, 36, 1))
>State : Symbol(State, Decl(index.tsx, 38, 22))
>Actions : Symbol(Actions, Decl(index.tsx, 38, 28))
>ActionsObject : Symbol(ActionsObject, Decl(index.tsx, 0, 0))
>State : Symbol(State, Decl(index.tsx, 38, 22))
>obj : Symbol(obj, Decl(index.tsx, 38, 67))
>Options2 : Symbol(Options2, Decl(index.tsx, 30, 3))
>State : Symbol(State, Decl(index.tsx, 38, 22))
>Actions : Symbol(Actions, Decl(index.tsx, 38, 28))
app2({
>app2 : Symbol(app2, Decl(index.tsx, 36, 1))
state: 100,
>state : Symbol(state, Decl(index.tsx, 40, 6))
actions: {
>actions : Symbol(actions, Decl(index.tsx, 41, 15))
foo: s => s // Should be typed number => number
>foo : Symbol(foo, Decl(index.tsx, 42, 14))
>s : Symbol(s, Decl(index.tsx, 43, 12))
>s : Symbol(s, Decl(index.tsx, 43, 12))
},
view: (s, a) => undefined as any,
>view : Symbol(view, Decl(index.tsx, 44, 6))
>s : Symbol(s, Decl(index.tsx, 45, 11))
>a : Symbol(a, Decl(index.tsx, 45, 13))
>undefined : Symbol(undefined)
});
type ActionsArray<State> = ((state: State) => State)[];
>ActionsArray : Symbol(ActionsArray, Decl(index.tsx, 46, 3))
>State : Symbol(State, Decl(index.tsx, 49, 18))
>state : Symbol(state, Decl(index.tsx, 49, 29))
>State : Symbol(State, Decl(index.tsx, 49, 18))
>State : Symbol(State, Decl(index.tsx, 49, 18))
declare function app3<State, Actions extends ActionsArray<State>>(obj: Options<State, Actions>): void;
>app3 : Symbol(app3, Decl(index.tsx, 49, 55))
>State : Symbol(State, Decl(index.tsx, 51, 22))
>Actions : Symbol(Actions, Decl(index.tsx, 51, 28))
>ActionsArray : Symbol(ActionsArray, Decl(index.tsx, 46, 3))
>State : Symbol(State, Decl(index.tsx, 51, 22))
>obj : Symbol(obj, Decl(index.tsx, 51, 66))
>Options : Symbol(Options, Decl(index.tsx, 2, 1))
>State : Symbol(State, Decl(index.tsx, 51, 22))
>Actions : Symbol(Actions, Decl(index.tsx, 51, 28))
app3({
>app3 : Symbol(app3, Decl(index.tsx, 49, 55))
state: 100,
>state : Symbol(state, Decl(index.tsx, 53, 6))
actions: [
>actions : Symbol(actions, Decl(index.tsx, 54, 15))
s => s // Should be typed number => number
>s : Symbol(s, Decl(index.tsx, 55, 14))
>s : Symbol(s, Decl(index.tsx, 55, 14))
],
view: (s, a) => undefined as any,
>view : Symbol(view, Decl(index.tsx, 57, 6))
>s : Symbol(s, Decl(index.tsx, 58, 11))
>a : Symbol(a, Decl(index.tsx, 58, 13))
>undefined : Symbol(undefined)
});
namespace JSX {
>JSX : Symbol(JSX, Decl(index.tsx, 59, 3))
export interface Element {}
>Element : Symbol(Element, Decl(index.tsx, 61, 15))
export interface IntrinsicElements {}
>IntrinsicElements : Symbol(IntrinsicElements, Decl(index.tsx, 62, 31))
}
interface ActionsObjectOr<State> {
>ActionsObjectOr : Symbol(ActionsObjectOr, Decl(index.tsx, 64, 1))
>State : Symbol(State, Decl(index.tsx, 66, 26))
[prop: string]: ((state: State) => State) | State;
>prop : Symbol(prop, Decl(index.tsx, 67, 5))
>state : Symbol(state, Decl(index.tsx, 67, 22))
>State : Symbol(State, Decl(index.tsx, 66, 26))
>State : Symbol(State, Decl(index.tsx, 66, 26))
>State : Symbol(State, Decl(index.tsx, 66, 26))
}
declare function App4<State, Actions extends ActionsObjectOr<State>>(props: Options<State, Actions>["actions"] & { state: State }): JSX.Element;
>App4 : Symbol(App4, Decl(index.tsx, 68, 1))
>State : Symbol(State, Decl(index.tsx, 70, 22))
>Actions : Symbol(Actions, Decl(index.tsx, 70, 28))
>ActionsObjectOr : Symbol(ActionsObjectOr, Decl(index.tsx, 64, 1))
>State : Symbol(State, Decl(index.tsx, 70, 22))
>props : Symbol(props, Decl(index.tsx, 70, 69))
>Options : Symbol(Options, Decl(index.tsx, 2, 1))
>State : Symbol(State, Decl(index.tsx, 70, 22))
>Actions : Symbol(Actions, Decl(index.tsx, 70, 28))
>state : Symbol(state, Decl(index.tsx, 70, 114))
>State : Symbol(State, Decl(index.tsx, 70, 22))
>JSX : Symbol(JSX, Decl(index.tsx, 59, 3))
>Element : Symbol(JSX.Element, Decl(index.tsx, 61, 15))
const a = <App4 state={100} foo={s => s} />; // TODO: should be number => number, but JSX resolution is missing an inferential pass
>a : Symbol(a, Decl(index.tsx, 72, 5))
>App4 : Symbol(App4, Decl(index.tsx, 68, 1))
>state : Symbol(state, Decl(index.tsx, 72, 15))
>foo : Symbol(foo, Decl(index.tsx, 72, 27))
>s : Symbol(s, Decl(index.tsx, 72, 33))
>s : Symbol(s, Decl(index.tsx, 72, 33))

View File

@ -0,0 +1,261 @@
=== tests/cases/compiler/index.tsx ===
interface ActionsObject<State> {
>ActionsObject : ActionsObject<State>
>State : State
[prop: string]: (state: State) => State;
>prop : string
>state : State
>State : State
>State : State
}
interface Options<State, Actions> {
>Options : Options<State, Actions>
>State : State
>Actions : Actions
state?: State;
>state : State | undefined
>State : State
view?: (state: State, actions: Actions) => any;
>view : ((state: State, actions: Actions) => any) | undefined
>state : State
>State : State
>actions : Actions
>Actions : Actions
actions: string | Actions;
>actions : string | Actions
>Actions : Actions
}
declare function app<State, Actions extends ActionsObject<State>>(obj: Options<State, Actions>): void;
>app : <State, Actions extends ActionsObject<State>>(obj: Options<State, Actions>) => void
>State : State
>Actions : Actions
>ActionsObject : ActionsObject<State>
>State : State
>obj : Options<State, Actions>
>Options : Options<State, Actions>
>State : State
>Actions : Actions
app({
>app({ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,}) : void
>app : <State, Actions extends ActionsObject<State>>(obj: Options<State, Actions>) => void
>{ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,} : { state: number; actions: { foo: (s: number) => number; }; view: (s: number, a: ActionsObject<number>) => any; }
state: 100,
>state : number
>100 : 100
actions: {
>actions : { foo: (s: number) => number; }
>{ foo: s => s // Should be typed number => number } : { foo: (s: number) => number; }
foo: s => s // Should be typed number => number
>foo : (s: number) => number
>s => s : (s: number) => number
>s : number
>s : number
},
view: (s, a) => undefined as any,
>view : (s: number, a: ActionsObject<number>) => any
>(s, a) => undefined as any : (s: number, a: ActionsObject<number>) => any
>s : number
>a : ActionsObject<number>
>undefined as any : any
>undefined : undefined
});
interface Bar {
>Bar : Bar
bar: (a: number) => void;
>bar : (a: number) => void
>a : number
}
declare function foo<T extends Bar>(x: string | T): T;
>foo : <T extends Bar>(x: string | T) => T
>T : T
>Bar : Bar
>x : string | T
>T : T
>T : T
const y = foo({
>y : { bar(x: number): void; }
>foo({ bar(x) { // Should be typed number => void }}) : { bar(x: number): void; }
>foo : <T extends Bar>(x: string | T) => T
>{ bar(x) { // Should be typed number => void }} : { bar(x: number): void; }
bar(x) { // Should be typed number => void
>bar : (x: number) => void
>x : number
}
});
interface Options2<State, Actions> {
>Options2 : Options2<State, Actions>
>State : State
>Actions : Actions
state?: State;
>state : State | undefined
>State : State
view?: (state: State, actions: Actions) => any;
>view : ((state: State, actions: Actions) => any) | undefined
>state : State
>State : State
>actions : Actions
>Actions : Actions
actions?: Actions;
>actions : Actions | undefined
>Actions : Actions
}
declare function app2<State, Actions extends ActionsObject<State>>(obj: Options2<State, Actions>): void;
>app2 : <State, Actions extends ActionsObject<State>>(obj: Options2<State, Actions>) => void
>State : State
>Actions : Actions
>ActionsObject : ActionsObject<State>
>State : State
>obj : Options2<State, Actions>
>Options2 : Options2<State, Actions>
>State : State
>Actions : Actions
app2({
>app2({ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,}) : void
>app2 : <State, Actions extends ActionsObject<State>>(obj: Options2<State, Actions>) => void
>{ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,} : { state: number; actions: { foo: (s: number) => number; }; view: (s: number, a: ActionsObject<number>) => any; }
state: 100,
>state : number
>100 : 100
actions: {
>actions : { foo: (s: number) => number; }
>{ foo: s => s // Should be typed number => number } : { foo: (s: number) => number; }
foo: s => s // Should be typed number => number
>foo : (s: number) => number
>s => s : (s: number) => number
>s : number
>s : number
},
view: (s, a) => undefined as any,
>view : (s: number, a: ActionsObject<number>) => any
>(s, a) => undefined as any : (s: number, a: ActionsObject<number>) => any
>s : number
>a : ActionsObject<number>
>undefined as any : any
>undefined : undefined
});
type ActionsArray<State> = ((state: State) => State)[];
>ActionsArray : ((state: State) => State)[]
>State : State
>state : State
>State : State
>State : State
declare function app3<State, Actions extends ActionsArray<State>>(obj: Options<State, Actions>): void;
>app3 : <State, Actions extends ((state: State) => State)[]>(obj: Options<State, Actions>) => void
>State : State
>Actions : Actions
>ActionsArray : ((state: State) => State)[]
>State : State
>obj : Options<State, Actions>
>Options : Options<State, Actions>
>State : State
>Actions : Actions
app3({
>app3({ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,}) : void
>app3 : <State, Actions extends ((state: State) => State)[]>(obj: Options<State, Actions>) => void
>{ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,} : { state: number; actions: ((s: number) => number)[]; view: (s: number, a: ((state: number) => number)[]) => any; }
state: 100,
>state : number
>100 : 100
actions: [
>actions : ((s: number) => number)[]
>[ s => s // Should be typed number => number ] : ((s: number) => number)[]
s => s // Should be typed number => number
>s => s : (s: number) => number
>s : number
>s : number
],
view: (s, a) => undefined as any,
>view : (s: number, a: ((state: number) => number)[]) => any
>(s, a) => undefined as any : (s: number, a: ((state: number) => number)[]) => any
>s : number
>a : ((state: number) => number)[]
>undefined as any : any
>undefined : undefined
});
namespace JSX {
>JSX : any
export interface Element {}
>Element : Element
export interface IntrinsicElements {}
>IntrinsicElements : IntrinsicElements
}
interface ActionsObjectOr<State> {
>ActionsObjectOr : ActionsObjectOr<State>
>State : State
[prop: string]: ((state: State) => State) | State;
>prop : string
>state : State
>State : State
>State : State
>State : State
}
declare function App4<State, Actions extends ActionsObjectOr<State>>(props: Options<State, Actions>["actions"] & { state: State }): JSX.Element;
>App4 : <State, Actions extends ActionsObjectOr<State>>(props: (string & { state: State; }) | (Actions & { state: State; })) => JSX.Element
>State : State
>Actions : Actions
>ActionsObjectOr : ActionsObjectOr<State>
>State : State
>props : (string & { state: State; }) | (Actions & { state: State; })
>Options : Options<State, Actions>
>State : State
>Actions : Actions
>state : State
>State : State
>JSX : any
>Element : JSX.Element
const a = <App4 state={100} foo={s => s} />; // TODO: should be number => number, but JSX resolution is missing an inferential pass
>a : JSX.Element
><App4 state={100} foo={s => s} /> : JSX.Element
>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

View File

@ -0,0 +1,77 @@
// @noImplicitAny: true
// @strictNullChecks: true
// @jsx: preserve
// @filename: index.tsx
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