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

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

TypeScript对象字段类型映射实现方案

问题分析

你之前的实现中,DataReturn<T>里的infer Item会把输入对象所有字段的类型合并成一个联合类型,导致每个字段的返回类型变成所有可能类型的集合。正确的思路是直接对每个字段做针对性的类型映射,不需要用infer。

基础实现:正确的类型映射

我们可以用TypeScript的映射类型直接遍历输入对象的每个键,根据对应的值类型映射到目标类型,同时用类型映射表简化维护:

// 定义输入类型标识到返回类型的映射表,新增类型只需在这里加键值对
type TypeMap = {
  'string': string;
  'boolean': boolean;
  'number': number;
};

// 输入对象类型:键为任意字符串,值为TypeMap的键
type DataDefinition = { [K: string]: keyof TypeMap };

// 返回类型:对输入对象的每个键K,返回TypeMap中对应的类型
type DataReturn<T extends DataDefinition> = {
  [K in keyof T]: TypeMap[T[K]];
};

const registerData = <T extends DataDefinition>(data: T): DataReturn<T> => {
  const result = {} as DataReturn<T>;
  // 模拟根据类型生成数据的逻辑
  for (const key in data) {
    const type = data[key];
    switch (type) {
      case 'string':
        result[key] = 'Lorem ipsum dolor sit amet' as TypeMap['string'];
        break;
      case 'boolean':
        result[key] = Math.random() > 0.5 as TypeMap['boolean'];
        break;
      case 'number':
        result[key] = Math.floor(Math.random() * 100) as TypeMap['number'];
        break;
    }
  }
  return result;
};

// 测试调用
const data = registerData({
  bodyText: 'string',
  isAdmin: 'boolean',
  postCount: 'number'
});

// 此时data的类型完全符合预期:
// {
//   bodyText: string;
//   isAdmin: boolean;
//   postCount: number;
// }

扩展:支持更多类型与自定义返回

如果需要区分类似int和float(最终都返回number[]),或者返回函数、数组等任意类型,只需扩展TypeMap和对应的生成逻辑即可:

// 扩展类型映射表,支持任意返回类型
type TypeMap = {
  'string': string;
  'boolean': boolean;
  'number': number;
  'int': number[];    // int类型返回数字数组
  'float': number[];  // float类型也返回数字数组
  'callback': () => void; // 返回函数类型
};

type DataDefinition = { [K: string]: keyof TypeMap };

type DataReturn<T extends DataDefinition> = {
  [K in keyof T]: TypeMap[T[K]];
};

const registerData = <T extends DataDefinition>(data: T): DataReturn<T> => {
  const result = {} as DataReturn<T>;
  for (const key in data) {
    const type = data[key];
    switch (type) {
      case 'string':
        result[key] = 'Lorem ipsum dolor sit amet' as TypeMap['string'];
        break;
      case 'boolean':
        result[key] = Math.random() > 0.5 as TypeMap['boolean'];
        break;
      case 'number':
        result[key] = Math.floor(Math.random() * 100) as TypeMap['number'];
        break;
      case 'int':
        result[key] = [1, 2, 3] as TypeMap['int'];
        break;
      case 'float':
        result[key] = [1.1, 2.2, 3.3] as TypeMap['float'];
        break;
      case 'callback':
        result[key] = () => console.log('Hello') as TypeMap['callback'];
        break;
    }
  }
  return result;
};

// 测试扩展类型
const extendedData = registerData({
  ids: 'int',
  prices: 'float',
  log: 'callback'
});

// extendedData的类型:
// {
//   ids: number[];
//   prices: number[];
//   log: () => void;
// }

原方案失败原因

你之前用T extends { [K in keyof T]: infer Item }时,infer Item会把T所有字段的类型合并成一个联合类型(比如'string' | 'boolean' | 'number'),然后每个字段都用这个联合类型去匹配DataReturnItem,最终导致每个字段的类型变成string | boolean | number。而直接用映射类型[K in keyof T]: TypeMap[T[K]]会逐个处理每个字段的具体类型,得到精准的映射结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 03:46:34