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

TypeScript中关联参数与返回值的泛型类型收窄实现方案

TypeScript实现多参数与返回值的类型关联收窄

问题场景

当前代码中,我们希望函数的参数a、b和返回值保持类型关联:当a的类型被收窄时,b和返回值的类型也同步收窄。但原代码使用泛型T extends NumberType | StringType时,TypeScript无法在switch块中自动关联b的类型,且返回值无法直接赋值给T,出现类型错误。

原示例代码:

type NumberType = {
    readonly type: "number"
    readonly value: number
}

type StringType = {
    readonly type: "string"
    readonly value: string
}

function test<T extends NumberType | StringType>(a: T, b: T): T {
    switch (a.type) {
        case "number": {
            console.log("Number case: ", a, b)
            const result: NumberType = {
                type: "number",
                value: a.value + b.value // 报错:b.value可能是string
            }
            return result // 报错:无法将NumberType赋值给T
        }
        case "string": {
            console.log("String case: ", a, b)
            const result: StringType = {
                type: "string",
                value: a.value + b.value // 报错:b.value可能是number
            }
            return result // 报错:无法将StringType赋值给T
        }
    }
}

解决方案

方法一:使用函数重载

函数重载可以明确指定不同输入类型对应的输出类型,让TypeScript精准识别参数与返回值的类型关联:

type NumberType = {
    readonly type: "number"
    readonly value: number
}

type StringType = {
    readonly type: "string"
    readonly value: string
}

// 重载签名:定义两种输入输出的类型关联
function test(a: NumberType, b: NumberType): NumberType;
function test(a: StringType, b: StringType): StringType;

// 实现签名:处理联合类型
function test(a: NumberType | StringType, b: NumberType | StringType) {
    switch (a.type) {
        case "number": {
            console.log("Number case: ", a, b)
            // 此时b会被自动收窄为NumberType
            return {
                type: "number",
                value: a.value + b.value
            }
        }
        case "string": {
            console.log("String case: ", a, b)
            // 此时b会被自动收窄为StringType
            return {
                type: "string",
                value: a.value + b.value
            }
        }
    }
}

方法二:泛型结合类型断言(简洁版)

如果希望保留泛型写法,可以通过类型断言告诉TypeScript当前分支的b和返回值类型与a一致:

type NumberType = {
    readonly type: "number"
    readonly value: number
}

type StringType = {
    readonly type: "string"
    readonly value: string
}

type ValueType = NumberType | StringType;

function test<T extends ValueType>(a: T, b: T): T {
    switch (a.type) {
        case "number": {
            console.log("Number case: ", a, b)
            const numB = b as NumberType;
            const result = {
                type: "number",
                value: a.value + numB.value
            } as T;
            return result;
        }
        case "string": {
            console.log("String case: ", a, b)
            const strB = b as StringType;
            const result = {
                type: "string",
                value: a.value + strB.value
            } as T;
            return result;
        }
    }
}

方法三:分布式条件类型优化泛型

通过定义分布式条件类型,让TypeScript自动推导类型关联:

type NumberType = {
    readonly type: "number"
    readonly value: number
}

type StringType = {
    readonly type: "string"
    readonly value: string
}

type ValueType = NumberType | StringType;

// 定义根据type字段获取对应类型的条件类型
type TypeByTag<T extends ValueType["type"]> = 
    T extends "number" ? NumberType : StringType;

function test<T extends ValueType["type"]>(
    a: TypeByTag<T>, 
    b: TypeByTag<T>
): TypeByTag<T> {
    switch (a.type) {
        case "number": {
            console.log("Number case: ", a, b)
            return {
                type: "number",
                value: a.value + b.value
            } as TypeByTag<T>;
        }
        case "string": {
            console.log("String case: ", a, b)
            return {
                type: "string",
                value: a.value + b.value
            } as TypeByTag<T>;
        }
    }
}

说明

  • 函数重载是最直观的方案,TypeScript会根据传入的参数类型自动匹配对应的重载签名,完美实现类型同步收窄。
  • 泛型方案适合需要复用类型逻辑的场景,通过类型断言或条件类型辅助TypeScript完成类型推导。

内容的提问来源于stack exchange,提问作者Lenny

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:30:57