TypeScript泛型与Record类型映射问题:批量转换Action函数类型
问题解决:批量转换Actions对象的类型
需求说明
我有如下结构的对象:
const actions = { foo: (state: string, action: {payload: string}) => {}, bar: (state: string, action: {payload: number}) => {}, baz: (state: string, action: {payload: boolean}) => {}, qux: (state: string) => {} }
同时我定义了如下泛型类型:
type ActionMapper<T> = T extends (state: any, action: infer Action) => any ? Action extends {payload: infer P} ? (payload: P) => void : VoidFunction : never
这个泛型可以提取单个函数(比如actions.foo())中action.payload的类型,生成对应的函数类型。我现在需要实现一个泛型,对整个actions对象完成同样的类型转换。
已尝试方案
我试过定义下面这个泛型:
type ActionsMapper<A> = Record<keyof A, ActionMapper<A[keyof A]>>
但结果不符合预期:它把所有函数的参数类型提取出来生成了联合类型,而不是为每个属性生成单独的正确类型(比如我期望mappedActions.foo()的类型是(payload: string) => void)。
解决方案
要实现针对对象每个属性单独处理的类型转换,需要使用映射类型配合索引访问的分布式条件类型,也就是在映射时对每个属性单独应用ActionMapper:
type ActionsMapper<A> = { [K in keyof A]: ActionMapper<A[K]> }
原理说明
原来的Record<keyof A, ActionMapper<A[keyof A]>>问题在于,A[keyof A]会先获取所有属性值的联合类型,然后ActionMapper对这个联合类型进行分布式条件类型处理,最终得到的是所有可能结果的联合类型,再把这个联合类型赋值给每个属性,导致所有属性的类型都一样。
而使用映射类型[K in keyof A]时,会遍历对象的每个键K,单独对A[K](也就是每个属性对应的函数类型)应用ActionMapper,这样每个属性都会得到对应的正确类型。
验证结果
用这个新的ActionsMapper处理actions对象,得到的类型会是:
type MappedActions = ActionsMapper<typeof actions> // 等价于: // { // foo: (payload: string) => void; // bar: (payload: number) => void; // baz: (payload: boolean) => void; // qux: VoidFunction; // }
内容的提问来源于stack exchange,提问作者ElohmroW
相关产品推荐
相关产品推荐

