redux - rootReducer=combineReducer produce tipul 'Never' cu typescript


Când combin reducerii mei, tipul setează reducerul rădăcină la Reducer1: niciodată, Reducer2: niciodată

Exemplu :

const rootReducer = combineReducers({
  stories: storyReducer,
  archivedStories: archiveReducer,
});

export type RootState = ReturnType<typeof rootReducer>;

storyReducer (IStory[] , StoryActionTypes)
archiveReducer (number[], ArchiveActionTypes)

Tipul iese în schimb ca,

povești: niciodată; poveștiArhivate: niciodată

Am urmat o altă sugestie de pe Stack Overflow și am încercat să specific tipul.

const rootReducer: Reducer<CombinedState<{stories: IStory[]; archivedStories: number[];}>, StoryActionTypes | ArchiveActionTypes> = combineReducers({
  stories: storyReducer,
  archivedStories: archiveReducer,
});

Dar încă încearcă să le map-eze la Never

Tipul 'Reducer<CombinedState<{ stories: never; archivedStories: never; }>, FetchStoriesAction | AddStoriesAction | ArchiveStoryAction>' nu poate fi atribuit tipului 'Reducer<{ stories: IStory[]; archivedStories: number[]; }, FetchStoriesAction | AddStoriesAction | ArchiveStoryAction>'. Tipurile de parametri 'state' și 'prevState' sunt incompatibile. Tipul '{ stories: IStory[]; archivedStories: number[]; }' nu poate fi atribuit tipului 'CombinedState<{ stories: never; archivedStories: never; }>'. Tipul '{ stories: IStory[]; archivedStories: number[]; }' nu poate fi atribuit tipului '{ stories: never; archivedStories: never; }'. Tipurile proprietății 'stories' sunt incompatibile. Tipul 'IStory[]' nu poate fi atribuit tipului 'never'.ts(2322)

Care este problema aici? Sau cum pot să specific corect tipul? Scopul meu este să folosesc .filter pe payload-ul IStory[] .

Acestea sunt reductoarele:

Reductor de povești

const INITIAL_STATE: IStory[] = []
  
const applyAddStories = (state: IStory[], action: StoryActionTypes) => action.payload;

export const storyReducer = (
  state = INITIAL_STATE,
  action: StoryActionTypes
) => {
  switch (action.type) {
    case STORIES_ADD : {
      return applyAddStories(state, action)
    }
    default:
      return state;
  }
};

Reducer de arhivă

const INITIAL_STATE: number[] = []

const applyArchiveStory = (state: number[], action: ArchiveActionTypes) => [
  ...state,
  action.payload,
];

export const archiveReducer = (
  state = INITIAL_STATE,
  action: ArchiveActionTypes

) => {
  switch (action.type) {
    case STORY_ARCHIVE: {
      return applyArchiveStory(state, action);
    }
    default:
      return state;
  }
};

export default archiveReducer;

Răspuns #1

Aș recomanda să impui tipul de returnare al reducer-ului tău. Este ceva ce îmi place să fac, deoarece ajută la verificarea tipurilor în implementarea reducer-ului:

//                                                           here
//                                                              v
function storyReducer(state: IStory[], action: StoryActionTypes): IStory[] {
  // ...
}

Nu va trebui să tastezi explicit reducerul, va funcționa pur și simplu cu codul tău original:

const rootReducer = combineReducers({
  stories: storyReducer,
  archivedStories: archiveReducer,
});

export type RootState = ReturnType<typeof rootReducer>;

Iată un teren de joacă care demonstrează rezultatul: link