具有通用类型的 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
创建生成操作
我在创建推断泛型类型的操作时遇到问题。
您遇到的问题似乎与 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]
解释器
AssingValueType
是 Discriminated Union Type,Category
是 AppliedFiltersType 的键,又名 'ships' | 'cars'
。
对于每个潜在的类别,我们也以类似的方式定义 filterKey
。 value
可以相对于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
应该像您预期的那样发挥魅力。
我正在尝试使用 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
创建生成操作
我在创建推断泛型类型的操作时遇到问题。
您遇到的问题似乎与 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]
解释器
AssingValueType
是 Discriminated Union Type,Category
是 AppliedFiltersType 的键,又名 'ships' | 'cars'
。
对于每个潜在的类别,我们也以类似的方式定义 filterKey
。 value
可以相对于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
应该像您预期的那样发挥魅力。