继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

TypeScript中的区分联合类型:轻松应对多种数据类型的高手技巧

哔哔one
关注TA
已关注
手记 457
粉丝 93
获赞 543

最初发表于https://antondevtips.com

什么是歧视联合

通常,应用程序需要能够处理多种输入或输出类型的变量和函数。对于这种需求,TypeScript 提供了一种称为“区分联合”的特殊联合类型,这种特殊联合类型也称为区分联合

标记联合类型在TypeScript中,由两种或多种其他类型组成。一个标记联合类型的变量可以是联合中定义的任何一种类型。

下面是一个简单的例子,变量可以存储一个数字或字符串:

    let id: number | string;  
    id = 100; // 这段代码没问题  
    id = "200"; // 这段代码没问题  

    // TypeScript 报错:类型 'boolean' 不能赋值给类型 'string | number'。  
    id = false; // 这里会报错

联合在拼接字符串字面量时也非常有用。字面量在TypeScript中是一种特殊的类型,常用于表示常量字符串。例如:

    let text: "TypeScript" = "TypeScript";  
    text = "TypeScript"; // 这段代码可以编译成功  

    // TypeScript 错误:类型 '"JavaScript"' 不能赋值给类型 '"TypeScript"'。  
    text = "JavaScript";

通过将具体的值组合在一起,你可以表明一个变量只能取一些特定的值。

    function print(value: string, align: "left" | "right" | "center") {  
        // ...  
    }  

    print("TypeScript types", "left")  

    // TypeScript 错误:"align" 参数应该是以下之一:"左" | "右" | "中"  
    print("TypeScript types", "middle");

当使用差异化联合体时,TypeScript只会让你访问这些类型共有的属性或方法。如果你想访问特定类型的属性或方法,你需要使用类型守卫来确定具体类型。

function 获取长度(obj: 字符串 | 字符串数组) {  
    if (typeof obj === "字符串") {  
        return obj.length; // 返回字符串长度  
    }  

    return obj.length; // 返回字符串数组的元素数量  
}
带有对象类型的联合类型

联合类型也可以结合对象类型。下面让我们通过一些几何图形的例子来探索,这些图形既有共同点又有不同之处:

    interface 圆形 = {  
        type: "circle";  
        半径: number;  
    };  

    interface 正方形 = {  
        type: "square";  
        边长: number;  
    };

让我们为每个形状创建一个计算面积的函数。

    function getSquare(shape: Circle | Square) {  
        if (shape.type === "circle") {  
            return Math.PI * shape.radius * shape.radius;  
        }  

        if (shape.type === "square") {  
            return shape.size * shape.size;  
        }  
    }  

    const circle: Circle = {  
        type: "circle",  
        radius: 10  
    };  

    const square: Square = {  
        type: "square",  
        size: 5  
    };  

    console.log("圆的面积: ", getSquare(circle));  
    console.log("正方形的面积: ", getSquare(square));

这里,getSquare 函数接收一个形状参数,这个参数可以是两种类型之一:CircleSquare。处理自定义类型时,你可以利用一个属性来区分不同的类型,比如我们的例子中使用的是 type 属性。这里的类型守卫非常简单直接:

// 计算形状的面积
function getSquare(shape: Circle | Square) {  
    // 如果形状是圆形,计算圆的面积
    if (shape.type === "circle") {  
        return Math.PI * shape.radius * shape.radius;  
    }  

    // 如果形状是正方形,计算正方形的面积
    if (shape.type === "square") {  
        return shape.side * shape.side;  
    }  

    return 0;  
}

TypeScript 能够识别我们正在处理的圆形或正方形类型。

使用区分联合作为函数返回值

另一个有用的场景是函数返回一个联合类型。让我们通过一个通过产品ID和所需数量订购产品的例子来探讨这种函数调用。这个函数的返回类型将是一个表示三种可能状态的联合类型:它可以表示成功、失败或未找到状态。

  • 订单创建成功啦
  • 找不到该产品
  • 仓库里的商品不够

简单的方法是声明一个包含所有三种情况的大对象,但这样做会比较麻烦。

歧视性联盟提供了一种更简洁的解决方案:

    type OrderResponse = OrderCreated | ProductNotFound | NoProductQuantity;  
    // 订单响应类型可以是订单创建成功、未找到产品或产品数量不足

    type OrderCreated = {  
        类型: "order-created";  
        orderId: string;  
        message: string;  
    };  
    // 订单创建成功的类型定义,包含订单ID和消息

    type ProductNotFound = {  
        类型: "product-not-found";  
        message: string;  
    };  
    // 未找到产品的类型定义,包含消息

    type NoProductQuantity = {  
        类型: "no-product-quantity";  
        message: string;  
    };  
    // 产品数量不足的类型定义,包含消息

现在我们可以用这种联合体类型作为函数的返回类型。为了简化,我们假设从数据库或外部 API 获取产品数据,但实际上我们会使用模拟数据。

    function orderProduct(productId: string, quantity: number): OrderResponse {  
        const productsDatabase = {  
            "Mobile Phone": { stock: 10 },  
            "Smart TV": { stock: 0 },  
        };  

        const product = productsDatabase[productId];  

        if (!product) {  
            return {  
                类型: "product-not-found",  
                消息: "找不到该商品"  
            };  
        }  

        if (quantity > product.stock) {  
            return {  
                类型: "no-product-quantity",  
                消息: "库存商品不足"  
            };  
        }  

        return {  
            类型: "order-created",  
            订单ID: `order-${new Date().getTime()}`,  
            消息: "订单已成功建立"  
        };  
    }

在这个函数中,我们将返回三种类型的响应:“订单创建成功”,“未找到产品”,“无产品库存”。要订购产品,我们可以调用这个方法。

    const orderResult = orderProduct("Mobile Phone", 1);  

    switch (orderResult.type) {  
        case "order-created":  
            console.log(`成功了:${orderResult.message} (订单号:${orderResult.orderId})`);  
            break;  
        case "product-not-found":  
            console.log(`出错了:${orderResult.message}`);  
            break;  
        case "no-product-quantity":  
            console.log(`出错了:${orderResult.message}`);  
            break;  
    }

正如你所见,区分联合体在这种情况下使代码更易读和更易维护。

总结

联合体类型在TypeScript中提供了一种有效的管理不同类型数据的方式。它们增强了类型的安全性,使代码更清晰,并确保所有可能的情况都被妥善处理,从而减少运行时错误。将联合体类型用作函数输入和输出类型将显著提高您的TypeScript应用程序的质量和可维护性。

希望这篇博客对你有用,编程开心!

最早发布于https://antondevtips.com

在看完帖子之后,请思考一下这些:
  • 订阅订阅以接收有关最新博客文章的邮件通知
  • 下载下载此帖子的源代码github(此源代码仅对我的BuyMeACoffee和Patreon赞助者开放)

如果你喜欢我的内容... 可以支持我一下

加入我的Patreon和“请我喝杯咖啡”社区,解锁我的博客文章中的源代码独家访问!

请支持我喝杯咖啡 请成为我的赞助者

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP