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

如何在TypeScript中实现类型安全的对象映射?

TypeScript对象映射:解决键类型丢失与可选属性问题

修复mapObject1:用类型断言补全键类型

Object.entries()会把对象的键统一转为string,导致Object.fromEntries()只能推断出字符串键的对象,和我们需要的{ [P in K]: B }类型不匹配。直接在返回结果上添加类型断言即可,这个断言是安全的——我们确实遍历了原对象的所有键,结构完全符合目标类型:

function mapObject1<K extends PropertyKey, A, B>(
  object: { [P in K]: A },
  mapper: (value: A) => B,
): { [P in K]: B } {
  return Object.fromEntries(
    Object.entries(object)
      .map(([key, value]) => [key, mapper(value)]),
  ) as { [P in K]: B };
}

修复mapObject2:两种方法消除可选属性

方法1:断言结果为必选类型

虽然初始化时result是可选属性,但我们通过forEach遍历了原对象的所有键并完成赋值,所以可以直接断言结果为目标的必选类型:

export function mapObject2<K extends PropertyKey, A, B>(
  object: { [P in K]: A },
  mapper: (value: A) => B,
): { [P in K]: B } {
  const result: { [P in K]?: B } = {};

  (Object.keys(object) as K[]).forEach((key: K) => {
    result[key] = mapper(object[key]);
  });

  return result as { [P in K]: B };
}

方法2:用reduce构建更贴合类型推断的对象(推荐)

换成reduce来构建结果,初始化时直接指定累加器的类型为目标类型,不需要声明可选属性,TypeScript能自动识别所有键都会被赋值:

export function mapObject2<K extends PropertyKey, A, B>(
  object: { [P in K]: A },
  mapper: (value: A) => B,
): { [P in K]: B } {
  return (Object.keys(object) as K[]).reduce((acc, key) => {
    acc[key] = mapper(object[key]);
    return acc;
  }, {} as { [P in K]: B });
}

进阶:支持symbol类型的键

如果你的对象可能包含symbol类型的键,Object.keys()和Object.entries()会忽略它们。改用Reflect.ownKeys()可以遍历所有类型的键:

function mapObject<K extends PropertyKey, A, B>(
  object: { [P in K]: A },
  mapper: (value: A) => B,
): { [P in K]: B } {
  const result = {} as { [P in K]: B };
  for (const key of Reflect.ownKeys(object) as K[]) {
    result[key] = mapper(object[key]);
  }
  return result;
}

这个版本兼容字符串、数字、symbol三种类型的键,适用性更广。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 16:05:25