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

xzabzqsa  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(159)

我正在使用@reduxjs/toolkit,并希望创建一个易于扩展的函数,该函数创建一个具有默认归约器的切片。我现在的实现可以工作,但不是强类型的。我如何创建一个函数,使切片的actions类型不仅包含默认归约器,还包含传入的归约器?我尝试过使用推理类型,但无法使其工作。
如有任何建议,我将不胜感激。谢谢。
最小示例:在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
      },
    },
  })
}

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
pod7payv

pod7payv1#

你真的很接近了,但有三个部分你错过了
1.必须使用泛型类型推断reducers的类型
1.您必须使用泛型reducers类型(即R)沿着提供的ValidateSliceCaseReducers类型,以决定reducers的结果类型。
1.使reducers类型成为必需的。我只能使它与所需的reducer一起工作,但可能有一种方法可以解决这个问题,但不太可能,因为类型来自@reduxjs/toolkit
注意:我只是将createStoreSlice属性拉到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

这是一个正在运行的TSPlayground
从他们的文档中看到这个例子,它解释得更好一点。

相关问题