Repository navigation
Closed
Labels
BugA bug in TypeScriptA bug in TypeScriptDomain: Conditional TypesThe issue relates to conditional typesThe issue relates to conditional typesFixedA PR has been merged for this issueA PR has been merged for this issue
Milestone
Description
TypeScript Version:
2.8.1, 2.9.2, 3.0.0-dev.20180628
Search Terms:
conditional type inference
Code
// Don't know what causes the problem so cannot come up with a shorter sample
type ActionType<P> = string & { attachPayloadTypeHack?: P & never }
/*
// irrelevant type to reproduce my issue
// but gives context that action might have no additional payload to handle
type Action<P> = P extends void
? { type: ActionType<P> }
: { type: ActionType<P>, payload: P }
*/
type Handler<S, P> = P extends void
? (state: S) => S
: (state: S, payload: P) => S
interface ActionHandler<S, P> {
actionType: ActionType<P>
handler: Handler<S, P>
}
declare function handler<S, P>(actionType: ActionType<P>, handler: Handler<S, P>): ActionHandler<S, P>
declare function createReducer<S>(
defaultState: S,
...actionHandlers: ActionHandler<S /* force state S for every action handler*/, any>[]
): any
interface AppState {
dummy: string
}
const defaultState: AppState = {
dummy: ''
}
const NON_VOID_ACTION: ActionType<number> = 'NON_VOID_ACTION'
, VOID_ACTION: ActionType<void> = 'VOID_ACTION'
handler<AppState, number>(NON_VOID_ACTION, (state, _payload) => state), // ok - state is AppState
handler<AppState, void>(VOID_ACTION, state => state) // ok - state is AppState
createReducer(
defaultState,
handler(NON_VOID_ACTION, (state, _payload) => state), // ok - state is AppState
handler(VOID_ACTION, state => state) // unexpected - state is any
)Expected behavior:
state parameter is infered to be "AppState" in the expression at the end
handler(VOID_ACTION, state => state)Actual behavior:
state parameter is infered to be "any"
Playground Link:
Playground
(use noImplicitAny flag)
Related Issues:
Not sure #25301
Workaround:
When Handler is defined as follows
type Handler<S, P> = (state: S, payload: P) => Sit still allows to pass single argument handler and state is infered to be AppState
Metadata
Metadata
Assignees
Labels
BugA bug in TypeScriptA bug in TypeScriptDomain: Conditional TypesThe issue relates to conditional typesThe issue relates to conditional typesFixedA PR has been merged for this issueA PR has been merged for this issue
Activity
weswigham commentedon Sep 11, 2018
This'd likely be fixed by #17819 if we're still interested in it. The root issue is that the apparent constraint of
P extends void ? (state: S) => S : (state: S, payload: P) => Sis(state: S) => S | (state: S, payload : P) => S. When looking at arrow functions to contextually type, we immediately discard signatures whose arity is smaller than what is written, which is why the two-argument case works (it narrows to one signature and is contextually typed appropriately), while the one-argument case does not (since both signatures are maybe-applicable and we give up).andriy-kudrya commentedon Sep 11, 2018
Thanks. While being not critical this feature is still relevant to my use case. I'm not sure should this issue be closed now. Latest build available at npm is 3.1.0-dev.20180907 so I cannot verify fix currently.
weswigham commentedon Sep 11, 2018
We haven't taken #17819 yet, so this issue should stay open. I just remarked that we already have a fix for another problem availablr that should also fix this.
weswigham commentedon Sep 13, 2018
Ryan Cavanaugh (@RyanCavanaugh) we need to revisit #17819 to fix this.