I'm using useReducer to maintain state for an array of object types and I have a few action types. The interfaces looks like:
interface MyObject { id: string; foo: string; bar: string; } interface Action { type: 'add' | 'remove' | 'update'; payload?: Partial<MyObject>; }
The reducer function:
const reducer = (current: MyObject[], action: Action): MyObject[] => { switch (action.type) { case 'add': return [...current, createBaseMyObject()]; case 'remove': return current.filter((item) => item.id !== action.payload?.id); case 'update': return current.map((item) => { if (item.id === action.payload?.id) { return { ...item, ...action.payload }; } return item; }); default: return current; } };
That works ok but I also need to conditionally pass an array of MyObject as the payload to update in bulk. Tried changing types and function to this:
interface ReducerAction { type: 'add' | 'remove' | 'update'; payload?: Partial<MyObject> | MyObject[]; } const reducer = (current: MyObject[], action: Action): MyObject[] => { switch (action.type) { case 'add': return [...current, createBaseMyObject()]; case 'remove': // Property 'id' does not exist on type 'MyObject[]' return current.filter((item) => item.id !== action.payload?.id); case 'update': // With proper typing maybe this should be dedicated case if (Array.isArray(action.payload)) { return action.payload; } return current.map((item) => { // Property 'id' does not exist on type 'MyObject[]' if (item.id === action.payload?.id) { return { ...item, ...action.payload }; } return item; }); default: return current; } };
I'm trying to avoid assertion or extra runtime checks just to satisfy TS. If creating a dedicated case makes it easier that's fine. I'd just want to type it best as possible and ideally keep it simple. Thoughts?
https://stackoverflow.com/questions/66847307/typing-reducer-payload-as-an-object-type-or-array-of-such March 29, 2021 at 08:04AM
没有评论:
发表评论