具有通用类型的 Redux 工具包 createAction

Redux toolkit createAction with generic type

我正在尝试使用 Redux 工具包 createAction 生成一个采用通用类型的操作。类型如下。

export interface ObjectArray {
    externalId: string
}

export interface CarFilters {
  arrayType: string[];
  objectType: ObjectArray[];
}

export type FilterOptionValue = string | number;

export type FilterMapValue = FilterOptionValue[] | string;

export interface ShipFilters {
  [key: number]: FilterMapValue;
}

type AppliedFiltersType = {
    cars: CarFilters;
    ships: ShipFilters;
}

type PathValue<T extends object, K extends keyof T = keyof T> = T[K] extends unknown ? T[K] : never;

export type AssingValueType<
  Category extends keyof AppliedFiltersType = keyof AppliedFiltersType, 
  Key extends keyof PathValue<AppliedFiltersType, Category> = keyof PathValue<AppliedFiltersType, Category>
> = {
  category: Category,
  filterKey: Key
  value: PathValue<AppliedFiltersType[Category], Key>;
}

Reducer 和动作

import { createAction, createReducer } from "@reduxjs/toolkit";

import { AssingValueType, AppState } from "./types";

export const updateAppliedFilterValue = createAction<AssingValueType>(
  "UPDATE_APPLIED_FILTER_VALUE"
);

const initialState = {
  appliedFilters: {
    cars: {
      arrayType: [],
      objectType: []
    },
    ships: {}
  }
} as AppState;

const reducerCreator = createReducer(initialState, (builder) => {
  builder.addCase(updateAppliedFilterValue, (state, action) => {
    state.appliedFilters[action.payload.category] = action.payload.value;
  });
});

export default reducerCreator;

目的是对操作参数进行严格的类型检查,这样它就不会被不一致的类型调用。

例如

updateAppliedFilterValue({ 类别:'car', 过滤键:1, 价值:3 })

应该被识别为ts编译器的错误。

像下面这样的纯函数有效

const updateFilterValues = <Category extends keyof AppliedFiltersType, Key extends keyof PathValue<AppliedFiltersType, Category>>(params: AssingValueType<Category, Key>) => {

  return params;
}

但我不清楚如何使用 createAction 创建生成操作 我在创建推断泛型类型的操作时遇到问题。

Codesandbox Link

您遇到的问题似乎与 AssigningValueType 的定义密切相关。

解决方案:

export type AssingValueType = {
  [Category in keyof AppliedFiltersType]:
    { category: Category } & {
      [Key in keyof AppliedFiltersType[Category]]: {
        filterKey: Key,
        value: PathValue<AppliedFiltersType[Category], Key>
      }
    }[keyof AppliedFiltersType[Category]]
}[keyof AppliedFiltersType]

解释器 AssingValueTypeDiscriminated Union TypeCategory 是 AppliedFiltersType 的键,又名 'ships' | 'cars'

对于每个潜在的类别,我们也以类似的方式定义 filterKeyvalue 可以相对于Category 和Key 进行定义。

& type intersection operator 用于合并 { filterKey, value } 和 { category }。

最后也是最重要的一步是 {[Category in keyof AppliedFiltersType]: ...}[keyof AppliedFiltersType] 它为 AppliedFiltersType 的每个键提取联合类型。

简而言之... {ships: {category: 'ships', ...}, cars: {category: 'cars', ...}} 变为 {category: 'cars' ...} | {category: 'ships'}

关于您最初的顾虑,createAction 应该像您预期的那样发挥魅力。