Typescript reducer 的 switch case typeguard 不适用于对象传播
Typescript reducer's switch case typeguard doesn't work with object spread
我有一个减速器根据 action.type
执行不同的操作,某些操作的操作负载不同。
export enum ActionType {
UpdateEntireState = "UPDATE_ENTIRE_STATE",
UpdateStateItem = "UPDATE_STATE_ITEM"
}
type TypeEditData = {
id: string;
name: string;
surname: string;
age: number;
};
export type State = TypeEditData[];
export type Action = UpdateEntireState | UpdateStateItem;
type UpdateEntireState = {
type: ActionType.UpdateEntireState;
payload: State;
};
type UpdateStateItem = {
type: ActionType.UpdateStateItem;
payload: { id: string; data: TypeEditData };
};
export function reducer(state: State, action: Action): State {
const { type, payload } = action;
switch (type) {
case ActionType.UpdateEntireState: {
return [...payload];
}
case ActionType.UpdateStateItem: {
const person = state.filter((item) => item.id === payload.id);
return [...state, person[0]];
}
default: {
throw Error("Wrong type of action!");
}
}
}
此代码无效,错误会提示我的操作负载可以是 State
或 { id: string; data: TypeEditData }
。
但是,如果我使用像这样的点符号访问 switch case 中的有效负载 属性
return [...action.payload];
不会有任何错误,类型保护会正常工作。
const { type, payload } = action;
在类型方面与 action.type
和 action.payload
有何不同?为什么 typeguard 不能使用扩展语法?
TS 版本 - 4.3.4
Action接口默认自带类型属性。
export interface Action {
type: string;
}
如果您可以扩展 Action 接口以将有效负载添加为对象数组,那么打字稿就不会抛出错误。
像这样,在你的 reducer 函数中你可以像这样使用
interface CustomAction extends Action{
payload: Array<any>
}
export function reducer(state: State, action: CustomAction): State {
问题是您在 action
上有类型信息可用之前定义了 payload
,因此它具有联合类型
State | {
id: string;
data: TypeEditData;
};
定义一个局部变量或简单地在每个 case 语句中使用 action.payload
,编译器知道它的类型:
export function reducer(state: State, action: Action): State {
// const { type, payload } = action;
switch (action.type) {
case ActionType.UpdateEntireState: {
return [...action.payload];
}
case ActionType.UpdateStateItem: {
const person = state.filter((item) => item.id === action.payload.id);
return [...state, person[0]];
}
default: {
throw Error("Wrong type of action!");
}
}
}
变量类型在声明时显式建立(例如const a: string
)或在初始化时隐式建立(例如a = 4
)。随后的类型保护构造不用于重新评估变量的类型。相反,由于此时已经定义了变量的类型,因此该类型用于验证后面的构造是否对该变量有效。
我有一个减速器根据 action.type
执行不同的操作,某些操作的操作负载不同。
export enum ActionType {
UpdateEntireState = "UPDATE_ENTIRE_STATE",
UpdateStateItem = "UPDATE_STATE_ITEM"
}
type TypeEditData = {
id: string;
name: string;
surname: string;
age: number;
};
export type State = TypeEditData[];
export type Action = UpdateEntireState | UpdateStateItem;
type UpdateEntireState = {
type: ActionType.UpdateEntireState;
payload: State;
};
type UpdateStateItem = {
type: ActionType.UpdateStateItem;
payload: { id: string; data: TypeEditData };
};
export function reducer(state: State, action: Action): State {
const { type, payload } = action;
switch (type) {
case ActionType.UpdateEntireState: {
return [...payload];
}
case ActionType.UpdateStateItem: {
const person = state.filter((item) => item.id === payload.id);
return [...state, person[0]];
}
default: {
throw Error("Wrong type of action!");
}
}
}
此代码无效,错误会提示我的操作负载可以是 State
或 { id: string; data: TypeEditData }
。
但是,如果我使用像这样的点符号访问 switch case 中的有效负载 属性
return [...action.payload];
不会有任何错误,类型保护会正常工作。
const { type, payload } = action;
在类型方面与 action.type
和 action.payload
有何不同?为什么 typeguard 不能使用扩展语法?
TS 版本 - 4.3.4
Action接口默认自带类型属性。
export interface Action {
type: string;
}
如果您可以扩展 Action 接口以将有效负载添加为对象数组,那么打字稿就不会抛出错误。 像这样,在你的 reducer 函数中你可以像这样使用
interface CustomAction extends Action{
payload: Array<any>
}
export function reducer(state: State, action: CustomAction): State {
问题是您在 action
上有类型信息可用之前定义了 payload
,因此它具有联合类型
State | {
id: string;
data: TypeEditData;
};
定义一个局部变量或简单地在每个 case 语句中使用 action.payload
,编译器知道它的类型:
export function reducer(state: State, action: Action): State {
// const { type, payload } = action;
switch (action.type) {
case ActionType.UpdateEntireState: {
return [...action.payload];
}
case ActionType.UpdateStateItem: {
const person = state.filter((item) => item.id === action.payload.id);
return [...state, person[0]];
}
default: {
throw Error("Wrong type of action!");
}
}
}
变量类型在声明时显式建立(例如const a: string
)或在初始化时隐式建立(例如a = 4
)。随后的类型保护构造不用于重新评估变量的类型。相反,由于此时已经定义了变量的类型,因此该类型用于验证后面的构造是否对该变量有效。