如何创建将参数转为返回类型部分的TypeScript泛型函数类型
实现参数与Payload严格匹配的TypeScript Action类型
嘿,我来帮你搞定这个TypeScript类型定义的问题!你想要的是让Actions接口里的每个函数,返回值的payload严格匹配它的参数结构,非法的结构会被TypeScript报错对吧?
首先得说,你原来的接口定义有个小问题:<T>(...args: T[])里的T是整个参数数组的类型,没法直接映射成payload的键值对结构。我们得换个思路,分两种场景来实现:
场景1:推荐用法——单个对象参数(最直观易维护)
这是Redux等状态管理库最推荐的写法,把所有参数打包成一个对象,这样payload就能直接和这个对象的类型完全对齐,类型检查精准,代码可读性也高。
类型定义
// 单个Action函数的类型:接收一个Payload对象,返回包含type和对应payload的结构 type ActionFunction<Payload extends object = {}> = (payload: Payload) => { type: string; payload: Payload; }; // Actions接口:每个属性都是ActionFunction类型 interface Actions { [fnName: string]: ActionFunction; }
示例用法
// 先定义几个业务类型 type SomeItemType = { id: number; name: string }; type SomeModeType = "soft" | "hard"; const someActions: Actions = { // ✅ 合法:payload和参数结构完全一致 addItem: (payload: { item: SomeItemType }) => ({ type: "ADD_NEW_ITEM", payload }), // ✅ 合法:参数是包含多个字段的对象,payload完美匹配 removeItem: (payload: { itemId: number; mode: SomeModeType }) => ({ type: "REMOVE_ITEM", payload }), // ❌ 非法:payload和参数结构不匹配,TypeScript会直接报错 // removeItem: (payload: { itemId: number; mode: SomeModeType }) => ({ // type: "REMOVE_ITEM", // payload: { id: 0 } // 类型不匹配,编辑器会提示错误 // }) };
场景2:支持多参数(不推荐,仅作参考)
如果你确实需要支持多个独立参数(比如(itemId: number, mode: SomeModeType)这种),我们可以用泛型元组把参数映射到payload里。但要注意:TypeScript的类型系统无法获取函数参数的名称,只能获取参数的位置和类型,所以payload的属性名只能是类似arg0、arg1这种基于位置的命名,不够直观。
类型定义
// 把参数元组映射成payload对象的类型 type ArgsToPayload<Args extends any[]> = { [K in keyof Args as `arg${K}`]: Args[K]; }; // 支持多参数的Action函数类型 type MultiArgActionFunction<Args extends any[]> = (...args: Args) => { type: string; payload: ArgsToPayload<Args>; }; // 多参数版本的Actions接口 interface MultiArgActions { [fnName: string]: MultiArgActionFunction<any[]>; }
示例用法
const multiArgActions: MultiArgActions = { // ✅ 合法:payload结构是 { arg0: number, arg1: SomeModeType } removeItem: (itemId: number, mode: SomeModeType) => ({ type: "REMOVE_ITEM", payload: { arg0: itemId, arg1: mode } }), // ❌ 非法:payload结构不匹配,TypeScript报错 // removeItem: (itemId: number, mode: SomeModeType) => ({ // type: "REMOVE_ITEM", // payload: { id: 0 } // 类型不匹配,编辑器提示错误 // }) };
总结
- 优先用单个对象参数的方案,它不仅能满足你的类型检查需求,还让代码结构更清晰,后续维护更方便。
- 多参数方案虽然能实现,但payload的命名不够直观,除非有特殊需求,否则不推荐使用。
内容的提问来源于stack exchange,提问作者ELP24
相关产品推荐
相关产品推荐

