TypeScript 2.8:简化类型安全缩减器?

时间:2018-04-23 13:16:31

标签: typescript

我正在阅读这篇文章https://medium.com/@martin_hotell/improved-redux-type-safety-with-typescript-2-8-2c11a8062575,我受到启发,通过ReturnType<A[keyof A]>基于typeof myActionFunction使用export interface MyFirstAction extends Action<MyEnum.FirstAction> { someProperty: string; } export interface MySecondAction extends Action<MyEnum.SecondAction> { someOtherProperty: number; } 来简化我的减速机。

然而,在翻译中似乎有些东西丢失了,因为如果我用

之类的东西明确地创建我的动作类型
export const reducer: Reducer<MyModel, Action> = (state: MyModel = initialState, action: MyFirstAction | MySecondAction) => {
    switch (action.type) {
        case MyEnum.FirstAction: {
            const x = action.someProperty; // x is string
            return state;
        }
        case MyEnum.SecondAction {
            const y = action.someOtherProperty; // y is number
            return state;
       }
    }
...

在我的减速机中,我可以做到

export const firstAction = (someProperty: string) => ({type: MyEnum.FirstAction, someProperty});
export const secondAction = (someOtherProperty: number) => ({type: MyEnum.SecondAction, someOtherProperty});

如果动作创建者是

type MyFirstAction = ReturnType<typeof firstAction>;
type MySecondAction = ReturnType<typeof secondAction>;

这是所有类型安全的,并且开箱即用,不幸的是,如果我使用

,它就不会
TS2339 Property 'someOtherProperty' does not exist on type ...

而不是明确声明我的Action接口。

E.g。在第二个case块中,我会得到像ReturnType这样的东西,因为如果使用wbVendor.Activate wsVendor.Activate Set CellPN = wsVendor.Application.InputBox _ (prompt:="Click in a cell which contains the part number in the vendors file.", Type:=8) CellPN.Parent.Parent.Activate 'Activate the workbook of CellPN CellPN.Parent.Select 'Select the worksheet of CellPN CellPN.Select 'Select CellPN ColumnPN = CellPN.Column AddressPN = CellPN.Address 而不是显式接口来推断类型,那么类型系统似乎无法区分它们。

为什么会这样,我能做些什么呢(这样我可以简化代码,减少锅炉板,并且同样开心)?

谢谢!

1 个答案:

答案 0 :(得分:1)

问题是Typescript不会推断对象文字属性的文字类型,因此{type: MyEnum.FirstAction, someProperty}的类型将是{type: MyEnum, someProperty: string }而不是{type: MyEnum.FirstAction, someProperty: string }。最简单的解决方案是使用类型断言来强制编译器推断文字类型而不是枚举类型:

type MyFirstAction = ReturnType<typeof firstAction>;
type MySecondAction = ReturnType<typeof secondAction>;

export const firstAction = (someProperty: string) => ({ type: MyEnum.FirstAction as MyEnum.FirstAction, someProperty });
export const secondAction = (someOtherProperty: number) => ({ type: MyEnum.SecondAction as MyEnum.SecondAction, someOtherProperty });

export const reducer: Reducer<MyModel, Action> = (state: MyModel = initialState, action: MyFirstAction | MySecondAction) => {
    switch (action.type) {
        case MyEnum.FirstAction: {
            const x = action.someProperty; // x is string
            return state;
        }
        case MyEnum.SecondAction: {
            const y = action.someOtherProperty; // y is number
            return state;
        }
    }
}