如何将任意{[k: string]: any}对象映射至TypeScript泛型Output类型
TypeScript 泛型函数映射API返回JSON到指定类型的解决方案
问题背景
现有一个返回Output泛型类型的函数,调用API得到JSON对象后,希望将其映射为指定的Output类型。示例代码如下:
function myFunc<Output>(): Promise<Output> { const apiRes: {[Key: string]: string} = getFromAPI() return apiRes as Output }
直接使用类型断言会触发TypeScript类型不匹配报错,需要实现类型安全的属性映射逻辑,但不清楚如何获取泛型Output的属性及对应值类型。
解决方案
1. 基于泛型约束与类型守卫的验证映射
先通过Record<string, unknown>约束Output为对象类型,再用类型守卫验证API返回值结构是否符合目标类型:
function myFunc<Output extends Record<string, unknown>>(): Promise<Output> { const apiRes: Record<string, string> = getFromAPI(); // 类型守卫:验证对象是否匹配Output结构 function isOutput(obj: unknown): obj is Output { if (typeof obj !== 'object' || obj === null) return false; return (Object.keys(obj as Output) as Array<keyof Output>).every(key => key in obj); } const mappedResult = apiRes as unknown as Output; if (isOutput(mappedResult)) { return Promise.resolve(mappedResult); } throw new Error("API返回结果不符合目标类型结构"); }
2. 显式遍历泛型属性做类型转换
利用keyof Output获取目标类型的所有属性键,结合Output[Key]获取对应值类型,实现针对性的类型转换:
function myFunc<Output extends Record<string, unknown>>(): Promise<Output> { const apiRes: Record<string, string> = getFromAPI(); const result = {} as Output; // 遍历目标类型的所有属性键 (Object.keys(result) as Array<keyof Output>).forEach(key => { const apiValue = apiRes[String(key)]; if (!apiValue) throw new Error(`API返回缺少属性:${String(key)}`); // 根据目标值类型做转换 switch (typeof result[key]) { case 'number': (result[key] as unknown) = Number(apiValue); break; case 'boolean': (result[key] as unknown) = apiValue === 'true' || apiValue === '1'; break; case 'string': (result[key] as unknown) = apiValue; break; default: throw new Error(`不支持转换为类型:${typeof result[key]}`); } }); return Promise.resolve(result); }
3. 传入自定义转换函数(最灵活)
让调用者提供转换逻辑,利用TypeScript的泛型推导确保类型安全:
function myFunc<Output>(transform: (apiRes: Record<string, string>) => Output): Promise<Output> { const apiRes: Record<string, string> = getFromAPI(); return Promise.resolve(transform(apiRes)); } // 调用示例 interface User { id: number; name: string; active: boolean; } myFunc(res => ({ id: Number(res.id), name: res.name, active: res.active === 'true' })).then(user => { // user类型自动推导为User,完全类型安全 });
关键知识点
keyof Output:获取泛型Output的所有属性键联合类型,比如Output为User时,结果是'id' | 'name' | 'active'。Output[Key]:通过属性键Key获取Output对应的值类型,实现类型针对性转换。Record<string, unknown>:约束泛型必须为对象类型,避免传入非对象类型导致逻辑错误。
内容的提问来源于stack exchange,提问作者Omar Tiamani
相关产品推荐
相关产品推荐

