Skip to content

Loss of type inference converting to named parameters object #29791

Closed
@yortus

Description

@yortus

Working on a strongly-typed wrapper for vuex modules, I've encountered an issue where I can't get type inference to work if I use a named parameters object, but it works perfectly if I use separate parameters.

The following is a cut-down repro showing two functions that are identical apart from how they take their parameters. I'd really prefer to use the named parameters object approach but no matter what I've tried, I can't get the type inference to work like it does with separate parameters. So for now I'm just having to pass separate parameters with comment labels (as shown below), which is far from ideal.

I'd like to know whether this is a bug, or I'm failing to understand some subtlety that accounts for the different treatment of tsc of separate parameters vs named parameter objects. If this behaviour is intended, is there any way to use named parameter objects without losing type inference?

TypeScript Version: 3.4.0-dev.20190206

Search Terms: named parameters object

Code

// takes separate parameters `state`, `mutations`, and `actions`
declare function separateParams<State, Mutations>(
    state: State,
    mutations: Mutations & Record<string, (_: State) => void>, // NB: contextual type uses State
    actions: Record<string, (_: Mutations) => void>            // NB: contextual type uses Mutations
): void;

// takes a named parameters object `{state: ..., mutations: ..., actions: ...}`
declare function namedParamsObj<State, Mutations>(obj: {
    state: State,
    mutations: Mutations & Record<string, (_: State) => void>, // NB: contextual type uses State
    actions: Record<string, (_: Mutations) => void>            // NB: contextual type uses Mutations
}): void;


// infers    State = {s1: number}   Mutations = {m1: (s: {s1: number}) => void}
separateParams(/*state:*/ {s1: 42}, /*mutations:*/ {m1: s => {}}, /*actions:*/ {a1: m => !m.m1});

// infers    State = {s1: number}   Mutations = {}
namedParamsObj({   state: {s1: 42},     mutations: {m1: s => {}},     actions: {a1: m => !m.m1}});
//                                       ERROR TS2339: 'm1' does not exist on type '{}' ----^^

Expected behavior:

Same type inference for both separateParams and namedParamsObj.

Actual behavior:

separateParams is perfectly typed. But type inference is much less useful in namedParamsObj despite its almost identical looking declaration.

Playground Link: here

Related Issues:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions