如何从TypeScript条件类型中推导运行时值?
解决TypeScript条件返回类型的运行时判断问题
问题描述
我正在为服务端与客户端之间的协议编写类型化包装器。该协议可返回单个或多个带值的响应:
- 若统一返回数组,单值场景下需额外校验,而绝大多数响应是单值,希望避免这种冗余校验。
- 因此基于多结果API名称的枚举定义了条件返回类型
Result<T>,标记为多结果的API返回数组,其他返回单值。
但TypeScript的类型信息会在运行时被擦除,done函数无法直接从Result<T>类型推导是否返回数组。现有代码如下(APIs枚举、IResultMapper接口和MultiResult类型为自动生成,可能包含数百个条目):
enum APIs { api1 = "API1", api2 = "API2", api3 = "API3", } type MultiResult = typeof APIs.api1 | typeof APIs.api2 ; interface IResultMapper { [APIs.api1]: { result: string[] }; [APIs.api2]: { values: string }; [APIs.api3]: { name: string }; } const values: string[] = []; function record(value: string): void { values.push(value); } type Result<T extends keyof IResultMapper> = T extends MultiResult ? string[] : string; function done<T extends keyof IResultMapper>(api: T, value: string): Result<T> { // 缺少运行时判断逻辑:isMultiResult如何确定? if (isMultiResult) { values.push(value); return values; } return value; }
解决方案
核心思路是将编译时的MultiResult类型映射为运行时可访问的集合,同时通过类型断言确保集合与类型的一致性,避免手动维护出错。
1. 生成运行时多结果API集合
创建一个与MultiResult类型完全匹配的常量数组,利用TypeScript的类型推导和编译时校验确保两者同步:
// 定义运行时的多结果API集合,与MultiResult类型一一对应 const multiResultAPIs = [APIs.api1, APIs.api2] as const; // 从集合推导类型,确保和MultiResult一致 type MultiResultRuntime = typeof multiResultAPIs[number]; // 编译时校验:如果集合和MultiResult类型不匹配,会报错 type _AssertTypeMatch<T, U> = T extends U ? U extends T ? true : never : never; type _CheckMultiResultConsistency = _AssertTypeMatch<MultiResult, MultiResultRuntime>;
2. 修改done函数实现运行时判断
利用上述集合判断当前API是否属于多结果类型,同时通过类型断言让TypeScript识别返回值的类型:
function done<T extends keyof IResultMapper>(api: T, value: string): Result<T> { // 运行时判断当前API是否在多结果集合中 const isMultiResult = multiResultAPIs.includes(api as MultiResultRuntime); if (isMultiResult) { values.push(value); // 类型断言:告诉TypeScript此时返回的是数组类型 return values as Result<T>; } // 类型断言:告诉TypeScript此时返回的是单值类型 return value as Result<T>; } // 调用示例 console.log(done(APIs.api1, "test")); // 返回数组:["test"] console.log(done(APIs.api3, "test")); // 返回单值:"test"
3. 适配自动生成场景
由于APIs、MultiResult等是自动生成的,你可以:
- 在代码生成工具(如OpenAPI Generator)中配置,同步生成
multiResultAPIs数组; - 若无法修改生成逻辑,可通过脚本从生成的TypeScript文件中提取
MultiResult的成员,自动生成该数组,避免手动维护。
内容的提问来源于stack exchange,提问作者Mike Lischke
相关产品推荐
相关产品推荐

