TypeScript:为嵌套返回对象实现嵌套输入对象键的自动补全
问题:工厂函数返回值的类型自动补全失效
我要创建一个工厂函数,接收配置参数后返回带自动补全能力的对象。功能已经实现,但返回值的部分类型自动补全不正常。
期望效果
const result = createSomething({ apis: { foo: { baseURL: "http://localhost:3000" }, bar: { baseURL: "http://localhost:3001" }, }, }); // foo 和 bar 应触发自动补全,且类型为`AxiosInstance` result.apis.foo result.apis.bar
当前失效的实现
我知道Object.entries处理时会丢失类型信息,试过类型断言但没解决。原本以为keyof typeof config.apis能满足,但自动补全的键只被识别为string类型:
const createSomething = (config: { apis: Record<string, CreateAxiosDefaults>; }) => { const apis = Object.entries(config.apis).reduce( (acc, [apiKey, axiosConfig]) => { acc[apiKey] = axios.create(axiosConfig); return acc; }, {} as Record<keyof typeof config.apis, AxiosInstance> ); return { apis, }; };
能实现补全但无法批量处理的方案
下面的代码能实现自动补全,但没法批量把Axios配置映射为实例:
const createSomething = (config: { apis: Record<string, CreateAxiosDefaults>; }) => { return { apis: { foo: axios.create(), bar: axios.create() } }; };
有没有替代Object.entries的方案能保留类型信息?输入和输出结构必须不变,实际场景里还有更多字段要保留。
解决方案
问题核心是你用了Record<string, CreateAxiosDefaults>作为apis的类型,这会让TypeScript丢失具体的键名信息。要保留自动补全,需要用泛型捕获传入apis的具体结构,而非宽泛的Record类型。
修改后的实现代码
import axios, { CreateAxiosDefaults, AxiosInstance } from 'axios'; const createSomething = <T extends Record<string, CreateAxiosDefaults>>(config: { apis: T; }) => { // 定义映射类型:将T的每个值类型从配置转为Axios实例 type ApiInstances = { [K in keyof T]: AxiosInstance; }; const apis = Object.entries(config.apis).reduce((acc, [apiKey, axiosConfig]) => { acc[apiKey as keyof T] = axios.create(axiosConfig); return acc; }, {} as ApiInstances); return { apis, // 保留原配置中的其他字段 ...config }; };
关键说明
- 泛型捕获具体结构:
<T extends Record<string, CreateAxiosDefaults>>让TypeScript自动推导传入apis的具体键名和结构,而非将其视为普通字符串键对象。 - 映射类型匹配输出:
ApiInstances通过遍历keyof T,把每个键对应的类型从CreateAxiosDefaults转为AxiosInstance,完美匹配输出结构。 - 类型断言消除报错:
apiKey as keyof T告知TypeScript当前遍历的键是T的合法键,避免类型不兼容报错。
效果验证
调用函数时,TypeScript会自动补全result.apis下的foo、bar等键,且它们的类型均为AxiosInstance,同时支持批量处理任意数量的API配置。
内容的提问来源于stack exchange,提问作者forgo
相关产品推荐
相关产品推荐

