You need to enable JavaScript to run this app. TypeScript 实现排序函数时如何从提取器类型推断关联值类型
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript 实现排序函数时如何从提取器类型推断关联值类型

通用排序函数的TypeScript类型推断问题梳理

需求背景

我们需要实现一个通用排序函数,核心能力是支持用户通过自定义函数,从待排序的对象中提取用于排序的依据字段,理想状态下应该能顺着提取函数的返回值,自动给比较器的参数匹配对应的类型,全程不需要手动补充类型标注。

最初实现的问题

我们最初为了实现泛型约束,定义了提取函数类型、配置对象接口:

// 提取函数的基础类型约束
type TKey<TData> = (data: TData) => any

interface SortingConfig<
  TData,
  TExtractor extends TKey<TData>,
  // 尝试通过条件类型从提取函数的签名里推导返回值类型
  TValue = TExtractor extends (data: TData) => infer R ? R : never
> {
  extractor: TExtractor,
  comparator?: (a: TValue, b: TValue) => number
}

// 接收数据和配置对象的函数定义
function test1<TData, TExtractor extends TKey<TData>>(
  value: TData,
  conf: SortingConfig<TData, TExtractor>
) {}

实际调用时出现了明显的推断割裂,具体表现为:

  • 传入待排序对象后,extractor的入参data能正确匹配为传入对象的类型(比如传入{a: number, b: string}类型的对象时,data会被推断为这个结构)
  • 但关联的comparator参数完全丢失类型,自动退化成(a: any, b: any) => any,完全没有拿到extractor返回值的类型

异常表现示例:

test1({
  a: 1,
  b: "string"
}, {
  // 这里extractor返回的是string类型(取b字段)
  extractor: data => data.b,
  // 期望comparator的参数是string类型,实际是any
  comparator: (a, b) => a
})

对照测试发现的正常场景

我们单独做了参数拆分的测试,把extractor和comparator从配置对象里拿出来作为独立函数参数传入,类型推断就完全正常了:

function test2<
  TData,
  TExtractor extends TKey<TData>,
  TValue = TExtractor extends (data: TData) => infer R ? R : never
>(
  data: TData, 
  extractor: TExtractor, 
  comparator: (a: TValue, b: TValue) => number
) {}

// 调用时类型完全匹配:extractor取a字段返回number,comparator的a、b参数自动推断为number类型
test2({a: 1, b: "string"}, data => data.a, (a, b) => a)

但这种拆分参数的写法不符合我们的配置聚合设计要求。

调整方案的缺陷

我们调整了泛型定义的逻辑,去掉了单独的TExtractor泛型参数,直接从extractor的函数签名推导TValue:

function test1<TData, TValue>(
  value: TData,
  conf: {
    extractor: (data: TData) => TValue,
    comparator: (a: TValue, b: TValue) => number
  }
) {}

这种写法下comparator的类型推断恢复正常,但彻底丢失了extractor入参的自动类型推断能力:如果调用时不手动给extractor的data参数标注类型,TS会直接把data推断成any,没有类型保护。

内容的提问来源于stack exchange,提问作者295

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 23:06:03