我正在阅读这篇文章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
而不是显式接口来推断类型,那么类型系统似乎无法区分它们。
为什么会这样,我能做些什么呢(这样我可以简化代码,减少锅炉板,并且同样开心)?
谢谢!
答案 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;
}
}
}