如何基于MkSelector泛型实现等价的BuildMkSelectors2类型?
问题解答:通过高阶类型复用MkSelector实现等价的BuildMkSelectors
可以实现这个需求。FOverRecord本质是一个高阶类型,它接收处理单个选择器的类型(如MkSelector<State>),将其转换为处理记录(Record)结构的类型,完全复用原类型的逻辑,最终让BuildMkSelectors2<State> = FOverRecord<MkSelector<State>>与原BuildMkSelectors<State>严格等价。
核心思路
FOverRecord需要完成两个核心映射:
- 输入端:将原类型接受的单个
MemoizeTuple,扩展为接受记录结构的MemoizeTuple集合 - 输出端:将原类型返回的单个选择器函数,扩展为返回对应记录结构的选择器函数集合
具体实现代码
基于你提供的现有类型定义,我们可以直接定义FOverRecord:
// 原有类型定义保持不变 type StateFunction<State> = (state: State) => any; type AnyFunction = (...args: any[]) => any; type ExtractReturnType<T extends AnyFunction[]> = { [I in keyof T]: ReturnType<T[I]>; }; type MemoizeTuple<T extends AnyFunction[]> = [ T, (...args: ExtractReturnType<T>) => any ]; type MkSelector<State> = <T extends StateFunction<State>[], F>( memoizeTyple: MemoizeTuple<[...T]> & F ) => F extends [infer _, infer B] ? (state: State) => B extends (...args: any[]) => infer R ? R : never : never; // 新增的FOverRecord高阶类型 type FOverRecord<SingleFn extends <T, F>(arg: T & F) => any> = <T extends Record<string, any>, F extends Record<keyof T, any>>( t: { [K in keyof T]: Parameters<SingleFn>[0] extends infer Arg ? Arg : never } & F ) => { [K in keyof F]: ReturnType<SingleFn extends (arg: any) => infer R ? R : never> extends (state: infer S) => infer Res ? (state: S) => Res : never; }; // 定义等价的BuildMkSelectors2 type BuildMkSelectors2<State> = FOverRecord<MkSelector<State>>;
等价性验证
我们可以通过实际使用来验证两者的等价性:
// 测试用State类型 interface TestState { user: { name: string; age: number }; posts: string[]; } // 使用原BuildMkSelectors const buildSelectors = {} as BuildMkSelectors<TestState>; const selectors1 = buildSelectors({ userName: [ [(s: TestState) => s.user], (user) => user.name ], postCount: [ [(s: TestState) => s.posts], (posts) => posts.length ] }); // selectors1类型:{ userName: (state: TestState) => string; postCount: (state: TestState) => number } // 使用BuildMkSelectors2 const buildSelectors2 = {} as BuildMkSelectors2<TestState>; const selectors2 = buildSelectors2({ userName: [ [(s: TestState) => s.user], (user) => user.name ], postCount: [ [(s: TestState) => s.posts], (posts) => posts.length ] }); // selectors2类型与selectors1完全一致:{ userName: (state: TestState) => string; postCount: (state: TestState) => number }
关键细节说明
FOverRecord通过Parameters<SingleFn>[0]提取原单键函数的输入类型,将其映射到记录的每个键上- 通过
ReturnType<SingleFn>提取原单键函数的返回类型,同样映射到输出记录的每个键上 - 利用TypeScript的条件类型和映射类型,确保完全复用
MkSelector的类型推导逻辑,没有重复实现
内容的提问来源于stack exchange,提问作者lisztz
相关产品推荐
相关产品推荐

