能否从常量对象提取类型列表?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
相关产品推荐
相关产品推荐

