我使用的是@reduxjs/toolkit,我想创建一个可轻松扩展的函数,该函数可以创建一个带有默认缩减器的切片.我现在拥有的实现可以工作,但不是强类型的.如何创建一个函数,使切片的操作类型不仅包含缺省的减法器,而且还包含传入的减法器?我曾try 使用推理类型,但无法使其起作用.

任何指导都将不胜感激.谢谢.

最小示例: 在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
      },
    },
  })
}

In 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 

推荐答案

你真的很接近,但你遗漏了三个部分

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

注:为了便于阅读,我刚把createStoreSlice个props 拉到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

这是一张TS Playground英镑的工作钞票

参见他们文档中的this个例子,更好地解释了这一点.

Typescript相关问答推荐

如何将函数类型应用到生成器?

使用新控制流的FormArray内部的Angular FormGroup

调用另一个函数的函数的Typescript类型,参数相同

TypeScript泛型参数抛出错误—?&#"' 39;预期"

属性的类型,该属性是类的键,其值是所需类型

类型脚本接口索引签名

如果存在ts—mock—imports,我们是否需要typescpt中的IoC容器

如何缩小变量访问的对象属性范围?

获取函数中具有动态泛型的函数的参数

在包含泛型的类型脚本中引用递归类型A<;-&B

诡异的文字类型--S为物语的关键

如何将定义模型(在Vue 3.4中)用于输入以外的其他用途

try 呈现应用程序获取-错误:动作必须是普通对象.使用自定义中间件进行MySQL操作

确保对象列表在编译时在类型脚本中具有唯一键

类型推断对React.ForwardRef()的引用参数无效

编剧- Select 动态下拉选项

在REACT查询中获取未定义的isLoading态

内联类型断言的工作原理类似于TypeScrip中的断言函数?

如何正确键入泛型相对记录值类型?

Angular 16:无法覆盖;baseUrl;在tsconfig.app.json中