Экспериментирую с useReducer, и столкнулся с такой проблемой. Например, есть массив каких-нибудь записей. Его надо получить, присвоить в стейт компонента, а потом вручную добавлять новые записи и удалять. Вопрос в том, как всё это дело правильно типизировать?
Я набросал
такой вариант, но меня смущает несколько моментов:
Во-первых, явное присваивание трех возможных типов в payload:
type ActionType = {
type: ActionPointsType;
payload: AlbumType | AlbumType[] | number;
};
Во-вторых, явное указание типов в return функции reducer (все эти "as AlbumType[]"):
switch (action.type) {
case ActionPoints.SET_ALBUMS:
return action.payload as AlbumType[];
case ActionPoints.ADD_ALBUM:
return [...state, action.payload] as AlbumType[];
case ActionPoints.REMOVE_ALBUM:
return state.filter((album) => album.id !== action.payload);
default:
return state;
}
В общем, как лучше типизировать функцию reducer и поля типа ActionType? Наверняка можно как-то применить здесь дженерики, но не могу сообразить, как именно. Пробовал, например, вот так:
type ActionType<T = any> = {
type: ActionPointsType
payload: T
};
// ...
const addNewAlbum = (event: React.FormEvent) => {
event.preventDefault();
const action: ActionType<AlbumType> = {
type: ActionPoints.ADD_ALBUM,
payload: {
id: albums.length + 1,
title: newAlbum
}
}
dispatch(action);
}
Ошибок никаких нет, но action.payload внутри функции reducer, а также albums в стейте моментально превращаются в any. Пробовал еще парочку вариантов, но везде какие-то свои косяки всплывают.
Второй вопрос, абстрагируясь от типизации - насколько мой вариант вообще, что называется, нормальный? Может, есть какие-либо более правильные или изящные способы реализовать подобную задачу?