Skip to content
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

Contextual inference not working in "nested" scenarios, inferred type is never #45041

Closed
kucharskimaciej opened this issue Jul 15, 2021 · 3 comments Β· Fixed by #45073
Closed

Contextual inference not working in "nested" scenarios, inferred type is never #45041

kucharskimaciej opened this issue Jul 15, 2021 · 3 comments Β· Fixed by #45073
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@kucharskimaciej
Copy link

Bug Report

πŸ”Ž Search Terms

Contextual inference
Does not exist on type 'never'

πŸ•— Version & Regression Information

Tested in 4+, and this is the behavior in every version I tried.

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type ModuleWithState<TState> = {
    state: TState;
}

type State = {
    a: number;
}

type MoreState = {
    z: string;
}

function createModule<TState, TActions>(state: TState, actions: TActions): ModuleWithState<TState> & TActions {
    return {
        state,
        ...actions
    }
}

function convert<TState, TActions>(m: ModuleWithState<TState> & TActions): ModuleWithState<TState & MoreState> & TActions {
    return {
        ...m,
        state: {
            ...m.state,
            z: "boo"
        },

    }
}


const breaks = convert(
    createModule({
        a: 12
    }, {
        foo() {
            return true
        }
    })
);

breaks.a; // Property 'a' does not exist on type 'never'.
breaks.z; // Property 'z' does not exist on type 'never'.
breaks.foo() // Property 'foo' does not exist on type 'never'.

const mod = createModule({
    a: 12
}, {
    foo() {
        return true
    }
})

const works = convert(mod);
works.a; // number
works.z // string
works.foo();

πŸ™ Actual behavior

The first scenario (breaks) fails the infer the correct type of the passed argument. Second scenario works works as expected. The only difference between the two is that in the latter the argument is first assigned to a variable.

πŸ™‚ Expected behavior

Both scenarios work exactly the same.

@devanshj
Copy link

devanshj commented Jul 15, 2021

You probably meant to write breaks.state.a, breaks.state.z, works.state.a, works.state.z instead (because that is what is expected to work according to the runtime code and types if I'm not reading it incorrectly). Also your playground link is inconsistent with the code.

This seems to be related to #40439. Because if you make foo a non-function say true then it starts working. TypeScript seems to topple with inference when there's a functional property in complex cases.

Here's a workaround

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Jul 15, 2021
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.5.0 milestone Jul 15, 2021
@RyanCavanaugh
Copy link
Member

@ahejlsberg the behavior in the playground link seems bad. Thoughts? Possibly related to #44476 (not sure) ?

@ahejlsberg ahejlsberg added Bug A bug in TypeScript and removed Needs Investigation This issue needs a team member to investigate its status. labels Jul 16, 2021
@ahejlsberg
Copy link
Member

@RyanCavanaugh It's a simple issue of not properly propagating the special silentNeverType in intersections. Trivial fix, will have a PR up soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants