我使用的是Typescript和Redux。有没有办法确保根据action
键入减速器的type
参数?这类似于实体框架将枚举列映射到适当的子类。
这是一个不完整的例子:
enum ActionType {
doThing1,
doThing2
}
interface Action {
readonly type: ActionType
}
interface Thing1Action extends Action {
readonly payload: Thing1Payload;
}
interface Thing2Action extends Action {
readonly payload: Thing2Payload;
}
interface State {
readonly thing1: Thing1Payload;
readonly thing2: Think2Payload;
}
const initialState: State = {
thing1: null,
thing2: null,
}
function reducer(state = initialState, action: Action): State {
switch (action.type)
{
case ActionType.doThing1:
return {...state, thing1: action.payload };
}
return state;
}
在上面的示例中,我想约束action.payload
来代表Thing1Payload
。现在,Typescript会抱怨action
没有payload
,或者当我省略action
的类型时,它会为我提供any
。
我只是在代码和编译时检查它。
答案 0 :(得分:3)
是的,这称为tagged union。在继承自Action
的每个接口中,您必须重新定义type
字段,但是使用适当的枚举文字类型键入它(基本上将单个可能的枚举值指定为字段的类型)。
然后使用所有派生接口定义联合类型,并将其用作参数类型。然后切换type
将充当类型保护。
enum ActionType {
doThing1,
doThing2
}
interface Action {
readonly type: ActionType
}
interface Thing1Payload {
b: number
}
interface Thing2Payload {
a: number
}
interface Thing1Action extends Action {
readonly type: ActionType.doThing1 // redefine the filed, only value assignable is ActionType.doThing1
readonly payload: Thing1Payload;
}
interface Thing2Action extends Action {
readonly type: ActionType.doThing2 // redefine the filed, only value assignable is ActionType.doThing2
readonly payload: Thing2Payload;
}
interface State {
readonly thing1: Thing1Payload;
readonly thing2: Thing2Payload;
}
const initialState: State = {
thing1: <Thing1Payload>null,
thing2: <Thing2Payload>null,
}
// Interface with all actions
type AllAction = Thing1Action | Thing2Action;
function reducer(state = initialState, action: AllAction): State {
// This switch will now be a type guard
switch (action.type) {
case ActionType.doThing1:
// action will be of typed Thing1Action
return { ...state, thing1: action.payload };
case ActionType.doThing2:
// action will be of typed Thing2Action
return { ...state, thing2: action.payload };
}
return state;
}