TypeScript API封装:基于输入键实现精确返回类型推导
解决方案:让TypeScript精确推断API封装的返回类型
你的核心问题是传入键数组后,TypeScript无法精确识别返回数组中对象的可用属性——原代码里返回类型用typeof arg[number]会把所有传入的键合并成联合类型,导致TypeScript认为返回对象包含所有映射后的属性,而非仅你指定的那些。下面是修复后的实现:
完整代码
type someType = { statuses?: string[], distances?: number[] // 所有数组长度一致 } type someOtherType = { status?: string, distance?: number } // 定义键映射关系,用as const让TypeScript保留字面量类型 const Mapping = { statuses: "status", distances: "distance" } as const; // 从Mapping中提取类型:someType的键对应到someOtherType的键 type KeyMapping = typeof Mapping; type SomeTypeKey = keyof someType; type MappedKey<K extends SomeTypeKey> = KeyMapping[K]; // 定义元组到对象类型的映射:遍历传入的键元组,生成仅包含对应映射属性的对象 type MapKeysToMapped<T extends readonly SomeTypeKey[]> = { [K in T[number]]-?: someOtherType[MappedKey<K>] }; function a<T extends readonly SomeTypeKey[]>(arg: T): MapKeysToMapped<T>[] { // 模拟API响应,确保类型是仅包含传入键的Required someType const someResponseObj = { statuses: ["active", "inactive"], distances: [100, 200] } as Required<Pick<someType, T[number]>>; // 获取数组长度(取第一个非空数组的长度,因为所有数组长度一致) const arrLength = Object.values(someResponseObj)[0]?.length ?? 0; const result: MapKeysToMapped<T>[] = []; for (let i = 0; i < arrLength; i++) { // 构建每个对象,reduce时确保类型正确 const mappedObj = arg.reduce((agg, key) => { const mappedKey = Mapping[key]; agg[mappedKey as keyof MapKeysToMapped<T>] = someResponseObj[key][i]; return agg; }, {} as MapKeysToMapped<T>); result.push(mappedObj); } return result; } // 测试效果 const b = a(["statuses"]); b[0].status; // ✅ 类型正确:string // b[0].distance; ❌ TypeScript会报错:属性'distance'不存在于类型'{ status: string; }' const c = a(["statuses", "distances"]); c[0].status; // ✅ string c[0].distance; // ✅ number
关键修改点
- 固定映射类型:把
Mapping用as const声明,让TypeScript保留每个键的字面量类型,而不是宽泛的keyof someOtherType。 - 元组遍历映射:
MapKeysToMapped<T>类型遍历传入的键元组T,生成仅包含对应映射属性的对象类型,而非合并所有可能的属性。 - 精确泛型约束:函数泛型
T extends readonly SomeTypeKey[]确保传入的是键的元组而非数组,保留每个元素的具体类型。 - 类型安全的reduce:初始化
agg为MapKeysToMapped<T>类型,避免不必要的类型断言,同时确保每个赋值的键都符合目标类型。
这样修改后,TypeScript就能完全根据你传入的键数组,精确推断返回数组中每个对象的可用属性,实现你需要的类型提示和校验。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

