Skip to content

Incorrect overload resolution in 3.2.0-rc #28567

Description

TypeScript Version: 3.2.0-rc

Search Terms:
Overload

Code

import { createStore } from 'redux'

const initialStore: { foo: {} } = { foo: {} }
const store = createStore(x => x, initialStore)

Expected behavior:

The second overload of createStore should be chosen, as initialStore is not a StoreEnhancer but a preloadedState.

Actual behavior:

The StoreEnhancer, a function, overload of createStore is chosen despite initialStore being absolutely, definitely not a function, causing the type of x to be incorrectly inferred as {} | undefined.

Activity

  1. ahejlsberg commented on Nov 17, 2018

    @ahejlsberg
    Member

    The error is not that we're picking the wrong overload, but rather that none of the overloads are applicable.

    Here's a simplified repro:

    declare function test<T>(f: (x: T | undefined) => T, enhancer: () => void): T;
    declare function test<T>(f: (x: T | undefined) => T, state: T): T;
    
    test(x => x, { a: 'hello' });  // Ok in 3.1, error in 3.2
    test(x => x || { a: 'xxx' }, { a: 'hello' });  // Ok in both

    The correct inference for T is { a: string } and therefore it is an error for the arrow function to return x ({ a: string } | undefined is not assignable to { a: string }).

    The reason it succeeds in 3.1 is somewhat subtle: We do multiple passes on the overloaded signatures, initially making an inference of { a: string } for T. In a later pass we end up with a contra-variant inference of { a: string } and a co-variant inference of { a: string } | undefined. In 3.1 we'd then go with the less specific inference of { a: string } | undefined, but in 3.2 we now prefer the more specific and more correct { a: string }. This changed in the commit here as part of #27028.

    The fact that 3.1 gets it wrong becomes obvious if you comment out the first overload (which shouldn't really matter as it is not applicable). 3.1 then behaves the same as 3.2.

  2. Jessidhia commented on Nov 19, 2018

    @Jessidhia
    Author

    I see. This is likely then an error with the redux type definitions -- if there is an initial state, then the reducer won't be called with undefined but rather with... the initial state.

  3. typescript-bot commented on Dec 13, 2018

    @typescript-bot
    Contributor

    This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  4. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Working as IntendedThe behavior described is the intended behavior; this is not a bug

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions