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

TypeScript中实现不同类型的类型安全代码分支的方法

类型安全实现基于参数类型的条件分支逻辑

你遇到的问题是TypeScript无法在泛型函数的条件分支中自动窄化Animal<Type>的具体类型,导致无法识别data的专属属性。以下是几种类型安全的解决方案:

方案一:使用区分联合类型(Discriminated Union)

将Animal定义为联合类型而非泛型,TypeScript会自动通过type属性完成类型窄化:

type Cat = {
    name: string;
    canMeow: boolean;
}

type Dog = {
    name: string;
    canBark: boolean
}

// 直接定义Animal为包含区分字段的联合类型
type Animal = 
  | { type: "cat"; data: Cat }
  | { type: "dog"; data: Dog };

function canMakeSound(animal: Animal){
    if(animal.type === "cat"){
        return animal.data.canMeow; // 类型自动窄化为Cat对应的Animal,无报错
    }
    else if(animal.type === "dog"){
        return animal.data.canBark; // 类型自动窄化为Dog对应的Animal,无报错
    }
    throw new Error("未知动物类型");
}

canMakeSound({type: "cat", data: {name: "kitty", canMeow: true}});

这种方案最简洁,是TypeScript处理此类场景的原生推荐方式,无需额外代码即可实现类型安全。

方案二:自定义类型守卫(Type Predicate)

如果需要保留泛型结构,可以通过自定义类型守卫函数帮助TypeScript识别分支中的具体类型:

type Cat = {
    name: string;
    canMeow: boolean;
}

type Dog = {
    name: string;
    canBark: boolean
}

type TypeMap = {
    dog: Dog;
    cat: Cat;
}

type Animal<T extends keyof TypeMap> = {
    type: T;
    data: TypeMap[T]
}

// 自定义类型守卫,判断是否为Cat类型的Animal
function isCat(animal: Animal<keyof TypeMap>): animal is Animal<"cat"> {
    return animal.type === "cat";
}

// 自定义类型守卫,判断是否为Dog类型的Animal
function isDog(animal: Animal<keyof TypeMap>): animal is Animal<"dog"> {
    return animal.type === "dog";
}

function canMakeSound(animal: Animal<keyof TypeMap>){
    if(isCat(animal)){
        return animal.data.canMeow; // 类型守卫生效,正确识别属性
    }
    else if(isDog(animal)){
        return animal.data.canBark; // 类型守卫生效,正确识别属性
    }
    throw new Error("未知动物类型");
}

canMakeSound({type: "cat", data: {name: "kitty", canMeow: true}});

这种方案适合需要复用类型判断逻辑,或者类型结构更复杂的场景。

方案三:类型断言(Type Assertion)

这是最直接但安全性最低的方式,仅当你能确保条件判断绝对正确时使用:

type Cat = {
    name: string;
    canMeow: boolean;
}

type Dog = {
    name: string;
    canBark: boolean
}

type TypeMap = {
    dog: Dog;
    cat: Cat;
}

type Animal<T extends keyof TypeMap> = {
    type: T;
    data: TypeMap[T]
}

function canMakeSound<Type extends keyof TypeMap>(animal: Animal<Type>){
    if(animal.type === "cat"){
        return (animal as Animal<"cat">).data.canMeow; // 手动断言类型
    }
    else if(animal.type === "dog"){
        return (animal as Animal<"dog">).data.canBark; // 手动断言类型
    }
}

canMakeSound({type: "cat", data: {name: "kitty", canMeow: true}});

类型断言会跳过TypeScript的类型检查,若后续类型定义变更,容易引发隐藏错误,因此不推荐作为常规方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 14:01:06