Skip to content

Generic type is not correctly inferred from the function return type when it is a function expression typeΒ #52114

@markostanimirovic

Description

@markostanimirovic

Bug Report

πŸ•— Version & Regression Information

Tested with different TS v4 versions. It does not seem like a regression.

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

// === Reproduction ===

export type ActionReducer<State> = (state: State | undefined) => State;

export function createReducer<State>(initialState: State): ActionReducer<State> {
    return {} as any;
}

export function createFeature<State>(config: {
    reducer: ActionReducer<State>,
    selectors: (state: State) => unknown,
}) {}

createFeature({
    reducer: createReducer(''),
    // the `state` type is `unknown`
    // if we remove `state` argument the error will disappear
    selectors: (state) => ({}),
    // selectors: () => ({})
});

// === Workarounds ===

// === Workaround 1:
// Define return type as another generic

export function createReducer2<
  State,
  Reducer extends ActionReducer<State> = ActionReducer<State>
>(initialState: State): Reducer {
    return {} as any;
}

createFeature({
    reducer: createReducer2(123),
    // the `state` type is correctly inferred (`number` in this case)
    selectors: (state) => ({})
});

More workarounds are available at the playground link.

πŸ™ Actual behavior

A generic type is not correctly inferred from the function return type when it is a function expression type.

By the way, I noticed that the State type will be correctly inferred when the ActionReducer from the example above is not defined as a function expression type:

// `ActionReducer` is not a function type anymore
export type ActionReducer<T> = T | undefined;

export function createReducer<T>(initialState: T): T {
    return {} as any;
}

export function createFeature<State>(config: {
    reducer: ActionReducer<State>,
    selectors: (state: State) => unknown,
}) {}

createFeature({
    reducer: createReducer(''),
    // the `state` type is correctly inferred
    selectors: (state) => ({}),
});

πŸ™‚ Expected behavior

I'd expect the same behavior when ActionReducer is typed as a function expression.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions