Skip to content

Type inference issue related to usage of conditional type #25299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
andriy-kudrya opened this issue Jun 28, 2018 · 4 comments
Closed

Type inference issue related to usage of conditional type #25299

andriy-kudrya opened this issue Jun 28, 2018 · 4 comments
Labels
Bug A bug in TypeScript Domain: Conditional Types The issue relates to conditional types Fixed A PR has been merged for this issue

Comments

@andriy-kudrya
Copy link

andriy-kudrya commented Jun 28, 2018

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) => S

it still allows to pass single argument handler and state is infered to be AppState

@weswigham
Copy link
Member

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) => S is (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
Copy link
Author

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
Copy link
Member

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
Copy link
Member

@RyanCavanaugh we need to revisit #17819 to fix this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: Conditional Types The issue relates to conditional types Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

6 participants