如何为 redux 切片及其操作创建强类型泛型函数?

Edw*_*win 8 typescript reactjs redux react-redux redux-toolkit

我正在使用@reduxjs/toolkit并想要创建一个易于扩展的函数,该函数使用默认的减速器创建一个切片。我现在的实现可以工作,但不是强类型的。如何创建一个函数,以便切片的操作类型不仅包含默认的减速器,还包含传入的减速器?我尝试过使用推理类型,但无法使其工作。

任何指导将不胜感激。谢谢。

最小示例:在common.ts文件中(其中逻辑可以在切片之间共享)

export interface StoreState<T> {
  data: T
  status: 'succeeded' | 'failed' | 'idle'
  error: string | null
}

// create a slice given a name and make it possible to extend reducers so they include more than just reset and updateStatus
export const createStoreSlice = <T>(props: {
  sliceName: string
  defaultState: T
  reducers?: SliceCaseReducers<StoreState<T>> // <-- want to infer this in slices/<sliceName>.ts
}) => {
  const { sliceName, reducers, defaultState } = props

  const initialState: StoreState<T> = {
    data: defaultState,
    status: 'idle',
    error: null,
  }

  return createSlice({
    name: sliceName,
    initialState,
    reducers: {
      ...reducers, // <--- want to somehow infer the type of this when exporting slice actions
      reset: (state) => {
        Object.assign(state, initialState)
      },
      updateStatus: (state, action) => {
        state.status = action.payload
      },
    },
  })
}

Run Code Online (Sandbox Code Playgroud)

slices/<sliceName>.ts(具有额外逻辑的特定切片)

export const genericSlice = createStoreSlice({
  sliceName: 'someSliceName',
  defaultState: { someField: 'some value' },
  reducers: {
    setSomeField: (state, action) => {
      const { payload } = action
      state.data.someField = payload
    },
  },
})

// these actions should be strongly typed from the createStoreSlice function parameters and contain the default reducers (eg. reset, updateStatus) and extra ones specific to the slice (eg. setSomeField)
export const { reset, updateStatus, setSomeField } = genericSlice.actions 
Run Code Online (Sandbox Code Playgroud)

Nic*_*yme 5

你们真的很接近,但还缺少三个部分

  1. reducers您必须使用泛型类型来推断 的类型
  2. 您必须使用泛型reducers类型(即R)以及提供的ValidateSliceCaseReducers类型来确定 的结果类型reducers
  3. 使reducers类型为必填项。我只能让它与所需的减速器一起工作,但可能有一种解决方法,但不太可能,因为类型来自@reduxjs/toolkit.

注意:我只是将createStoreSliceprops 拉到类型中StoreSliceProps以使其更易于阅读。

import { SliceCaseReducers, createSlice, ValidateSliceCaseReducers } from '@reduxjs/toolkit';

export interface StoreState<T> {
  data: T;
  status: 'succeeded' | 'failed' | 'idle';
  error: string | null;
}

interface StoreSliceProps<T, R extends SliceCaseReducers<StoreState<T>>> {
  sliceName: string;
  defaultState: T;
  reducers: ValidateSliceCaseReducers<StoreState<T>, R>;
}

export function createStoreSlice<T, R extends SliceCaseReducers<StoreState<T>>>(props: StoreSliceProps<T, R>) {
  const { sliceName, reducers, defaultState } = props;

  const initialState: StoreState<T> = {
    data: defaultState,
    status: 'idle',
    error: null,
  };

  return createSlice({
    name: sliceName,
    initialState,
    reducers: {
      ...reducers,
      reset: (state) => {
        Object.assign(state, initialState);
      },
      updateStatus: (state, action) => {
        state.status = action.payload;
      },
    },
  });
};

export const genericSlice = createStoreSlice({
  sliceName: 'someSliceName',
  defaultState: { someField: 'some value' },
  reducers: {
    setSomeField: (state, action) => {
      const { payload } = action;
      state.data.someField = payload;
    },
  },
});

export const { reset, updateStatus, setSomeField, fakeReducer } = genericSlice.actions; // only fakeReducer throws error as unknown as expected
Run Code Online (Sandbox Code Playgroud)

这是一个正在运行的TS Playground

请参阅他们的文档中的这个示例,它可以更好地解释它。