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

TypeScript中mapValue函数回调参数的类型窄化问题

为对象值重映射函数编写精确的TypeScript类型声明

我正在为一个用于重映射对象值的函数编写TypeScript类型声明,函数的使用示例如下:

const result = mapValue(
  {
    foo: "a",
    bar: 10,
    baz: true,
  },
  [
    ["foo", (value) => `thing ${value}`],
    ["bar", (value) => value - 1],
  ]
);

result; // { foo: "thing a", bar: 9 }

该函数的第二个参数是一个二维数组,每个元素包含要重映射的键和用于计算新值的回调函数。目前我遇到的核心问题是:无法将传递给映射回调的参数类型正确窄化。例如,对于映射项["foo", (value) => value],value的类型被推断为string | number | boolean,但它应该被窄化为仅string类型。

以下是类型安全性不足的初步版本:

declare function mapValue<T, TKey extends keyof T, TResult>(
  obj: T,
  mapping: Array<[TKey, (x: T[TKey]) => TResult]>,
): Record<typeof mapping[number][0], ReturnType<typeof mapping[number][1]>>;

我尝试使用映射类型逐步推断mapping参数,但TypeScript无法从TMapped[i][0]中正确推断类型:

declare function mapValue<T, const TMapping>(
  obj: T,
  mapping: {
    [i in keyof TMapping]: TMapping[i] extends [infer key, any] ? [TMapping[i][0], (value: T[key]) => unknown] : never
  },
): "todo";

解决方案

要实现精确的类型推断,需要让TypeScript为每个映射项单独关联对应的键类型和值类型,同时正确推导返回对象的结构。可以通过以下类型声明实现:

type MapEntry<T, K extends keyof T> = [K, (value: T[K]) => unknown];

declare function mapValue<
  T extends object,
  M extends MapEntry<T, keyof T>[]
>(
  obj: T,
  mapping: readonly [...M]
): {
  [K in M[number][0]]: (Extract<M[number], [K, any]>[1]) extends (v: any) => infer R ? R : never
};

使用这个类型声明后,示例中的value参数会被正确窄化:

  • 对应foo的回调参数类型为string
  • 对应bar的回调参数类型为number
    返回值result的类型会被精确推断为{ foo: string; bar: number },完全符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 09:19:50