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

能否从常量对象提取类型列表?TypeScript数组对象转换需求

TypeScript 实现数组与结构化对象的类型安全转换

你需要的是一套能在数组和对象之间双向转换、同时兼顾编译时类型校验和运行时类型检查的工具,下面是具体实现方案:

优化类型定义模板

原来用Number()这类实例作为类型标记不合适,换成构造函数本身——既可以在JavaScript中获取类型校验的依据,也能让TypeScript精确推导类型:

const SaveDataTemplate = {
  id: Number,
  name: String,
  someBool: Boolean,
} as const; // 用`as const`锁定模板结构,确保TS能推导精确的键顺序和类型

实现GetKeyTypesFrom类型工具

这个类型工具会提取模板中每个字段对应的目标类型,按模板的键顺序生成严格的元组类型:

// 提取对象键的有序元组(TS 2.9+支持对象键顺序保留)
type ObjectKeys<T extends object> = keyof T extends infer K
  ? K extends string
    ? (
        (T extends Record<K, unknown> ? { [P in K]: P } : never)[K]
      )[]
    : never
  : never;

// 根据模板生成数组元组类型
type GetKeyTypesFrom<T extends Record<string, new () => unknown>> = {
  [K in keyof T]: T[K] extends new () => infer U ? U : never;
}[ObjectKeys<T>];

// 生成目标数组类型
type tSaveData = GetKeyTypesFrom<typeof SaveDataTemplate>;
// 此时tSaveData的类型为 [number, string, boolean]

类型安全的双向转换函数

数组转对象:fromSaveData

添加编译时类型校验和运行时类型检查,避免非法数据导致的隐性错误:

function fromSaveData(data: tSaveData): { [K in keyof typeof SaveDataTemplate]: GetKeyTypesFrom<typeof SaveDataTemplate>[number] } {
  const returnObj = {} as { [K in keyof typeof SaveDataTemplate]: unknown };
  const templateKeys = Object.keys(SaveDataTemplate) as Array<keyof typeof SaveDataTemplate>;

  // 校验数组长度匹配模板字段数
  if (data.length !== templateKeys.length) {
    throw new Error('输入数组长度与模板字段数量不匹配');
  }

  templateKeys.forEach((key, idx) => {
    const ValueType = SaveDataTemplate[key];
    const value = data[idx];

    // 运行时类型校验:兼容原始类型和实例(比如new Number(1)和1)
    const isTypeValid = typeof value === ValueType.name.toLowerCase() || value instanceof ValueType;
    if (!isTypeValid) {
      throw new Error(`字段${String(key)}类型错误:期望${ValueType.name},实际为${typeof value}`);
    }

    returnObj[key] = value;
  });

  return returnObj as { [K in keyof typeof SaveDataTemplate]: GetKeyTypesFrom<typeof SaveDataTemplate>[number] };
}

对象转数组:toSaveData

同样加入双重校验,确保输入对象符合模板要求:

function toSaveData(data: { [K in keyof typeof SaveDataTemplate]: GetKeyTypesFrom<typeof SaveDataTemplate>[number] }): tSaveData {
  const returnArr: unknown[] = [];
  const templateKeys = Object.keys(SaveDataTemplate) as Array<keyof typeof SaveDataTemplate>;

  templateKeys.forEach(key => {
    // 校验必填字段存在
    if (!(key in data)) {
      throw new Error(`输入对象缺少必填字段:${String(key)}`);
    }

    const ValueType = SaveDataTemplate[key];
    const value = data[key];

    const isTypeValid = typeof value === ValueType.name.toLowerCase() || value instanceof ValueType;
    if (!isTypeValid) {
      throw new Error(`字段${String(key)}类型错误:期望${ValueType.name},实际为${typeof value}`);
    }

    returnArr.push(value);
  });

  return returnArr as tSaveData;
}

使用示例

// 数组转对象
const saveArray: tSaveData = [1001, "Alice", true];
const userData = fromSaveData(saveArray);
// userData类型:{ id: number; name: string; someBool: boolean }

// 对象转数组
const newUserData = { id: 1002, name: "Bob", someBool: false };
const newSaveArray = toSaveData(newUserData);
// newSaveArray类型:[number, string, boolean]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 03:47:04