Tengo un reductor que realiza diferentes acciones según el action.type de acción, la carga útil de las acciones es diferente para ciertas acciones.
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!"); } } } Este código no funcionará, los errores dirán que mi carga útil de acción puede ser State o { id: string; data: TypeEditData } . Sin embargo, si accedo a la propiedad de carga útil dentro de la caja del interruptor usando notación de puntos como esta
return [...action.payload]; No habrá ningún error y el tipo de protección funcionará bien. Cómo const { type, payload } = action; difiere de action.type y action.payload en términos de tipos y ¿por qué typeguard no funciona con sintaxis extendida?
Versión TS - 4.3.4
El problema es que definió la payload antes de que hubiera información de tipo disponible en action , por lo que tiene el tipo de unión
State | { id: string; data: TypeEditData; }; Defina una variable local o simplemente use action.payload dentro de cada declaración de caso y el compilador sabrá qué tipo tiene:
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!"); } } } El tipo de variable se establece explícitamente en la declaración (por ejemplo, const a: string ) o implícitamente en la inicialización (por ejemplo a = 4 ). Las construcciones de protección de tipos posteriores no se utilizan para volver a evaluar el tipo de la variable. Por el contrario, dado que el tipo de la variable ya está definido en ese punto, ese tipo se utiliza para validar si la construcción posterior es válida para la variable.
La interfaz de acción por defecto viene con la propiedad de tipo.
export interface Action { type: string; }Si puede extender la interfaz de Acción para agregar la carga útil como una matriz de objetos, el mecanografiado no arrojará un error. Algo como esto, en su función reductora puede usar así
interface CustomAction extends Action{ payload: Array<any> } export function reducer(state: State, action: CustomAction): State {