【问题标题】:How can I type a prop of an object depending on another prop's type?如何根据另一个道具的类型键入对象的道具?
【发布时间】:2020-02-16 17:56:49
【问题描述】:

考虑下一个例子:

enum ActionTypes {
    A = 'A',
    B = 'B'
}

type ActionProps = {
    [ActionTypes.A]: {
        a: string
    }
    [ActionTypes.B]: {
        b: string
    }
}

type Action = {
    [type in keyof ActionProps]: {
        type: type
    } & ActionProps[type]
}

//produces the expected result, but not ideal for the case

const state1: Action[ActionTypes] = {
    type: ActionTypes.A,
    a: 'string',
};

(() => {
    if (state1.type === ActionTypes.A) {
        state1.a = 'anotherstring';
        //doesn't error, because the compiler knows
        //the possible properties by state.type
    }
})();

//doesn't produce the expected result, but it would be ideal for the case

type State = {
    type: ActionTypes
    actionProps: ActionProps[State['type']]
}

const state2: State = {
    type: ActionTypes.A,
    actionProps: {
        a: 'string',
        b: 'string',
    }
};

(() => {
    if (state2.type === ActionTypes.A) {
        state2.actionProps.a = 'anotherstring';
        //errors - Property 'a' does not exist on type '{ b: string; }'
    }
})();

Playground

预期的结果是,如果编译器知道state.type === ActionTypes.A,它就知道state.actionProps 的类型是ActionProps[ActionTypes.A]

是否有任何可能的解决方法?

【问题讨论】:

  • 我不明白“产生了预期的结果,但不适合这种情况”。为什么不理想?如果你想要这种基于控制流的缩小范围,你需要一个有区别的联合,Action[keyof ActionProps] 正是正确的类型。那么有什么不适合你呢?

标签: javascript typescript types


【解决方案1】:

您可能正在寻找一个通用的:

enum ActionTypes {
    A = 'A',
    B = 'B'
}

type ActionProps = {
    [ActionTypes.A]: {
        a: string
    }
    [ActionTypes.B]: {
        b: string
    }
}

type State<Type extends keyof ActionProps> = {
    type: Type
    actionProps: ActionProps[Type] & ActionProps[keyof ActionProps]
}

const state: State<ActionTypes.A> = {
    type: ActionTypes.A,
    actionProps: {
        a: 'string',
        b: 'string',
    }
};

(() => {
    if (state.type === ActionTypes.A) {
        state.actionProps.a = 'anotherstring';
        //errors - Property 'a' does not exist on type '{ b: string; }'
    }
})();

但是,TypeScript 似乎无法根据.type 属性的值推断类型参数,该功能似乎是为discriminated unions 保留的。

【讨论】:

    猜你喜欢
    • 2019-07-23
    • 1970-01-01
    • 1970-01-01
    • 2019-02-07
    • 2020-12-21
    • 2021-12-08
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    相关资源
    最近更新 更多