You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 05:25:44