Я пытаюсь создать собственный хук React, используя useReducer. Предполагается, что он хранит состояние для массива объектов, и все объекты должны иметь поле «id». Структура объекта, отличная от идентификатора, должна быть общей.
Вот что у меня есть;
export enum ArrayActions { INIT, ADD, UPDATE, DELETE }
type ArrayAction<T> =
| { type: ArrayActions.INIT, payload: T[] }
| { type: ArrayActions.ADD, payload: T }
| { type: ArrayActions.UPDATE, payload: T }
| { type: ArrayActions.DELETE, id: string }
type ObjWithId = { id:any, [key: string]: any }
function arrayReducer<T extends ObjWithId>(state: T[], action: ArrayAction<T>): T[] {
switch(action.type){
case ArrayActions.INIT:
return [...action.payload]
case ArrayActions.ADD: // TODO: check if id already exists
return [...state, action.payload]
case ArrayActions.UPDATE:
return [...(state.filter(item => item.id !== action.payload.id)), action.payload]
case ArrayActions.DELETE:
return state.filter(item => item.id !== action.id)
}
}
export function useArrayReducer<T extends ObjWithId> (initialState: T[] = []): [T[], React.Dispatch<ArrayAction<T>>] {
const [state, dispatch] = useReducer(arrayReducer, initialState)
return [state, dispatch] // error!
}
state в последней строке выдает следующую ошибку;
Type 'ObjWithId[]' is not assignable to type 'T[]'.
Type 'ObjWithId' is not assignable to type 'T'.
Я думал, что это может быть связано с определением ObjWithId, но не мог точно понять это. Не могли бы вы помочь мне достичь желаемого результата?





В случае, если это кому-то нужно;
export interface ListItem {
id: string | number | undefined;
[key: string]: any;
}
export type Action<L extends ListItem> =
| { type: "init", items: L[]}
| { type: "add", item: L }
| { type: "update", item: L }
| { type: "delete", id: NonNullable<L["id"]>}