You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:26:11