【TS】TypeScript类型断言:掌握类型转换的艺术

news2025/1/23 9:07:12

鑫宝Code

🌈个人主页: 鑫宝Code
🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础
💫个人格言: "如无必要,勿增实体"


文章目录

  • TypeScript类型断言:掌握类型转换的艺术
    • 1. 引言
    • 2. 什么是类型断言?
    • 3. 类型断言的基本语法
      • 3.1 尖括号语法
      • 3.2 as语法
    • 4. 类型断言的常见用途
      • 4.1 处理any类型
      • 4.2 处理联合类型
      • 4.3 在类型收窄中使用
    • 5. 双重断言
    • 6. const断言
    • 7. 非空断言
    • 8. 类型断言与类型转换的区别
    • 9. 类型断言的最佳实践
    • 10. 类型断言的潜在风险
    • 11. 高级用例:类型断言在泛型中的应用
    • 12. 类型断言与接口
    • 13. 实际应用示例
    • 14. 结论

TypeScript类型断言:掌握类型转换的艺术

1. 引言

在TypeScript的类型系统中,类型断言是一个强大而有用的特性。它允许开发者告诉编译器某个值的具体类型,即使TypeScript无法自动推断出这个类型。本文将深入探讨TypeScript中的类型断言,包括其定义、使用方法、最佳实践以及注意事项,帮助您更好地理解和应用这一重要概念。
在这里插入图片描述

2. 什么是类型断言?

类型断言是一种告诉编译器"相信我,我知道我在做什么"的方式。它类似于其他语言中的类型转换,但不进行特殊的数据检查和重构。类型断言纯粹是一个编译时语法,不会影响程序的运行时行为。

3. 类型断言的基本语法

TypeScript提供了两种语法来进行类型断言:

3.1 尖括号语法

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

3.2 as语法

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

注意:在JSX中,只能使用as语法。

4. 类型断言的常见用途

4.1 处理any类型

当处理any类型的数据时,类型断言可以帮助我们恢复类型检查:

function getLength(something: any): number {
    if (something as string) {
        return (something as string).length;
    }
    return 0;
}

4.2 处理联合类型

当处理联合类型时,类型断言可以帮助我们访问特定类型的属性:

interface Bird {
    fly(): void;
    layEggs(): void;
}

interface Fish {
    swim(): void;
    layEggs(): void;
}

function getSmallPet(): Fish | Bird {
    // ...
}

let pet = getSmallPet();
(pet as Fish).swim();

4.3 在类型收窄中使用

类型断言可以在类型守卫之外进行类型收窄:

function isString(value: unknown): value is string {
    return typeof value === 'string';
}

function processValue(value: unknown) {
    if (isString(value)) {
        console.log(value.toUpperCase());
    } else {
        console.log(value as number * 2);
    }
}

5. 双重断言

在某些极端情况下,我们可能需要使用双重断言:

function handleEvent(event: Event) {
    const mouseEvent = event as unknown as MouseEvent;
    console.log(mouseEvent.clientX, mouseEvent.clientY);
}

注意:双重断言应该非常谨慎地使用,因为它可能导致运行时错误。

6. const断言

TypeScript 3.4引入了const断言,它可以让我们创建完全不可变的类型:

let x = "hello" as const;
// Type is literally "hello"

let arr = [1, 2, 3] as const;
// Type is readonly [1, 2, 3]

7. 非空断言

在这里插入图片描述

非空断言操作符 ! 可以用来断言一个表达式的值不为null或undefined:

function getValue(): string | null {
    return Math.random() > 0.5 ? "Hello" : null;
}

const value = getValue();
console.log(value!.toUpperCase());

8. 类型断言与类型转换的区别

类型断言只在编译时起作用,不会进行任何运行时的类型检查或转换:

let num: any = "123";
let numAsNumber = num as number;
// numAsNumber的类型是number,但它的值仍然是字符串"123"

相比之下,类型转换会在运行时进行实际的值转换:

let num: any = "123";
let numAsNumber = Number(num);
// numAsNumber的类型是number,它的值是数字123

9. 类型断言的最佳实践

  1. 优先使用类型守卫:当可能的时候,使用类型守卫而不是类型断言。类型守卫提供了运行时的类型检查。

    function isString(value: unknown): value is string {
        return typeof value === 'string';
    }
    
    function processValue(value: unknown) {
        if (isString(value)) {
            console.log(value.toUpperCase());
        }
    }
    
  2. 避免过度使用any:尽量不要使用any类型,而是使用更具体的类型或unknown。

  3. 使用as const来创建字面量类型:当你想要TypeScript推断出最具体的类型时,使用as const。

  4. 谨慎使用非空断言:只在你确定值不会是null或undefined时使用非空断言。

  5. 在JSX中使用as语法:在JSX中,只能使用as语法进行类型断言。

10. 类型断言的潜在风险

虽然类型断言是一个强大的工具,但它也带来了一些潜在的风险:

  1. 运行时错误:类型断言可能导致运行时错误,因为它绕过了TypeScript的类型检查。

    let num: any = "not a number";
    let square = (num as number) * (num as number);
    // 这会在运行时抛出错误
    
  2. 隐藏类型错误:过度使用类型断言可能会隐藏真正的类型错误,使代码更难维护。

  3. 破坏类型安全:不恰当的类型断言可能会破坏TypeScript提供的类型安全保证。

11. 高级用例:类型断言在泛型中的应用

类型断言在处理泛型时特别有用:

function create<T>(Class: { new(): T }): T {
    return new Class();
}

class Lion {
    roar() {
        console.log('Roar!');
    }
}

const lion = create(Lion) as Lion;
lion.roar(); // OK

12. 类型断言与接口

类型断言可以帮助我们在使用接口时更灵活:

interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
    return {
        color: config.color || "red",
        area: config.width ? config.width * config.width : 20,
    };
}

let mySquare = createSquare({ colour: "red", width: 100 } as SquareConfig);

13. 实际应用示例

让我们通过一个实际的应用示例来展示类型断言的使用:

// 假设我们从API获取了一些数据
interface ApiResponse {
    data: unknown;
    status: number;
}

interface User {
    id: number;
    name: string;
    email: string;
}

async function fetchUser(id: number): Promise<User> {
    const response: ApiResponse = await fetch(`/api/users/${id}`).then(res => res.json());
    
    if (response.status !== 200) {
        throw new Error(`Failed to fetch user: ${response.status}`);
    }

    // 使用类型断言来处理unknown类型
    const user = response.data as User;

    // 进行一些运行时检查
    if (typeof user.id !== 'number' || typeof user.name !== 'string' || typeof user.email !== 'string') {
        throw new Error('Invalid user data');
    }

    return user;
}

// 使用函数
async function displayUserInfo(id: number) {
    try {
        const user = await fetchUser(id);
        console.log(`User ${user.name} (${user.email}) has id ${user.id}`);
    } catch (error) {
        console.error(error);
    }
}

displayUserInfo(1);

在这个例子中,我们使用类型断言来处理API返回的unknown类型的数据。我们将其断言为User类型,但同时也进行了运行时检查以确保数据的正确性。这种方法结合了类型断言的灵活性和运行时检查的安全性。

14. 结论

TypeScript的类型断言是一个强大的工具,它允许开发者在特定情况下覆盖TypeScript的类型推断。然而,它应该被谨慎使用,因为过度依赖类型断言可能会导致运行时错误和类型安全问题。

最佳实践是尽可能依赖TypeScript的类型推断和类型守卫,只在必要时使用类型断言。当使用类型断言时,应该确保你比TypeScript编译器更了解值的实际类型。

通过合理使用类型断言,我们可以在保持代码类型安全的同时,处理一些TypeScript类型系统无法自动推断的复杂情况。这使得TypeScript成为一个更加灵活和强大的工具,能够适应各种编程场景。

随着您在实际项目中不断实践,您会发现类型断言是TypeScript工具箱中的一个重要工具,能够帮助您编写更加健壮和可维护的代码。继续探索和学习,相信您会在TypeScript的类型系统中发现更多精彩!

End

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1978134.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于特性价值来确认测试重点

目录 核心特性&#xff1a; 潜力特性&#xff1a; 噱头特性&#xff1a; 辅助特性&#xff1a; 无人问津的特性&#xff1a; 测试重点的确立&#xff1a; 软件的特性包含如下几种&#xff0c;核心特性&#xff0c;潜力特性&#xff0c;噱头特性&#xff0c;无人问津特性&…

Project Euler_Problem 277_A Modified Collatz Sequence

原题目&#xff1a; 题目大意&#xff1a; 一串字母可以视作迭代过程中每一轮除3余多少&#xff0c;问最小的大于1e15的满足那串序列的数是多大 解题思路&#xff1a;可以把那一大串字母&#xff0c;看作是不停地对初始数值x做连续运算&#xff0c;且每一轮运算的结果都应当是…

03:【stm32】GPIO

GPIO 1、芯片的引脚分布2、IO复用与重映射3、片上外设GPIO3.1、GPIO的寄存器组3.2、8种工作模式3.3、最大输出速度3.4、GPIO的内部结构 1、芯片的引脚分布 STM32F103C8T6这款芯片一共有48个引脚&#xff0c;他们分为了特殊功能引脚和普通的IO引脚。其中特殊功能的引脚有如下几个…

一键搬运TEMU、SHEIN店铺起新店。商品一键复制,商品裂变,TEMU商品复制

店铺搬家&#xff0c;一键搬运TEMU、SHEIN店铺起新店。商品一键复制&#xff0c;裂变新类目。铺店群必备 店铺搬家是什么&#xff1f; 店铺搬家就是将Temu一个店铺的所有商品快速搬到另一个店铺&#xff0c;只需要半个小时就能起一个全新的店铺&#xff0c;可以帮助商家快速起新…

comfyUI-MuseTalk的参数设置

comfyUI-MuseTalk的参数设置 目录 comfyUI-MuseTalk的参数设置 一、ComfyUI-VideoHelperSuite 二、comfyUI-MuseV合成的参考视频 2.1、什么时候会用到MuseV&#xff1f; 2.2、MuseV特别消耗系统内存 2.2.1、测试图片序列的像素比 2.2.2、影响运动范围和生成结果的参数 …

无法安装Python包,出现OSError: 拒绝访问错误

无法安装Python包&#xff0c;出现OSError: 拒绝访问错误 在安装Python包时&#xff0c;可能会遇到各种错误&#xff0c;其中“OSError: 拒绝访问”是一个比较常见的问题。这个错误通常表明在安装过程中&#xff0c;Python没有足够的权限去访问某个文件或目录。本文将深入探讨…

【LeetCode】45.跳跃游戏II

1. 题目 2. 分析 很久没有写贪心的题了&#xff0c;在这题上卡了很久时间&#xff0c;我这个还是不会贪心。 核心思想就一句话&#xff1a;维护在到达本次最远位置之前能达到的最远位置。每到边界时就更新步数&#xff0c;便得到正确答案。 3. 代码 class Solution:def jum…

微软商店无法加载,检查你的连接-解决方案

微软商店默认直连国内的服务器。 如果有代理&#xff0c;关闭代理就可以恢复网络了。 但是我就是想用代理&#xff0c;我感觉代理更快&#xff0c; 搜索了很多办法&#xff0c;都没有生效。 然后我在哔哩哔哩的视频下方&#xff0c;看到大家留言&#xff0c;测试了一下&#x…

Qt/C++项目积累: 2.主机监控器 - 2.3 实时数据及其他功能完善

相关链接&#xff1a; 链接1&#xff1a;Qt/C项目积累&#xff1a; 2.主机监控器 - 2.1 项目介绍-CSDN博客https://blog.csdn.net/qq_22122811/article/details/140254896 链接2&#xff1a;Qt/C项目积累&#xff1a; 2.主机监控器 - 2.2 历史功能实现-CSDN博客https://blog.…

ARM 架构硬件新趋势:嵌入式领域的未来

目录 目录 一、ARM 架构概述 二、新趋势一&#xff1a;AI 加速器集成 三、新趋势二&#xff1a;更高效的电源管理 四、新趋势三&#xff1a;安全性增强 五、结语 随着物联网 (IoT) 和边缘计算的发展&#xff0c;ARM 架构在嵌入式系统中的应用越来越广泛。从智能手机到智能…

STM32H7无RTOS应用堆栈机制与检测

摘要&#xff1a;单片机堆栈溢出会引发不可预知的错误。本文探讨了基于STM32CubeIDE设置STM32H7xx堆栈在无RTOS时的使用与检测方法。 一、堆栈的设置 STM32CubeIDE对工程设置堆栈很简单&#xff0c;在CubeMX中设置最小size如下图 堆&#xff08;Heap&#xff09;为0x400&#…

低空经济-低空智联网技术体系白皮书

目录 低空定义 低空政策 低空市场规模 低空应用场景 通信需求 监管需求 低空智联网技术体系 低空定义 低空经济是指在3000米以下&#xff0c;以低空空域为依托&#xff0c;以各种有人和无人驾驶航空器的低空飞行活动为牵引&#xff0c;辐射带动相关领域融合发展的综合性…

【MySQL是怎样运行的 | 第三篇】MySQL的MVCC机制

文章目录 3.MySQL的MVCC机制3.1前言3.2undo log日志3.3三个隐藏字段3.4undo log版本链3.5当前读VS快照读3.6ReadView3.7举例3.7.1RC&#xff08;读已提交&#xff09;3.7.2RR&#xff08;可重复读&#xff09; 3.8扩展&#xff1a;RR能解决幻读问题吗&#xff1f; 4.白云 3.MyS…

【Python系列】深入理解 Python 中的 `nonlocal` 关键字

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

进程状态(二)----- linux 中具体的进程状态(上)

目录 前言1. R 状态2. S 状态3. D 状态 前言 继上一篇文章 进程状态&#xff08;一&#xff09;---- 运行&#xff0c;阻塞&#xff0c;挂起 介绍了操作系统都有的三个进程状态&#xff0c;而这篇文章则是将进程状态具象化&#xff0c;谈论具体到 linux 系统中的进程状态都有哪…

Geoserver源码解读七 插件(二)扩展图层预览界面

系列文章目录 Geoserver源码解读一 环境搭建 Geoserver源码解读二 主入口 Geoserver源码解读三 GeoServerBasePage Geoserver源码解读四 REST服务 Geoserver源码解读五 Catalog Geoserver源码解读六 插件&#xff08;怎么在开发模式下使用&#xff09; 目录 系列文章目录…

vector中 resize()和reserve()

1.resize()改变容器大小 resize除了预留内存以外&#xff0c;还会调用容器元素的构造函数&#xff0c;不仅分配了N个对象的内存&#xff0c;还会构造N个对象。从这个层面上来说&#xff0c;resize()在时间效率上是比reserve()低的。 2.reserve()容器大小管理 用于预留内存。 …

【Linux】shell命令与Linux权限的概念

目录 一、shell命令二、Linux权限的概念2.1 Linux权限的概念2.1.1 用户2.1.2 指令2.1.2.1 su指令2.1.2.2 sudo指令 2.2 Linux权限管理2.2.1 文件访问者的分类&#xff08;人&#xff09;2.2.2 文件类型和访问权限&#xff08;事物属性&#xff09;2.2.2.1 文件类型2.2.2.2 基本…

C++ 中迭代器的first和second

c 里面的map容器的迭代器里面 有个first 和 second&#xff0c;分别指向键值和数值 it.first就是在迭代器中获取map键值&#xff0c;it.second同理 #include<iostream> #include<map> using namespace std;int main(void){map<string, string> m;//新建一个m…

lower_bound函数和upper_bound函数

lower_bound 和 upper_bound 函数都是 C 标准库算法&#xff0c;用于在已排序的范围内查找元素。它们返回的是迭代器&#xff0c;指向满足特定条件的元素位置。 lower_bound(begin, end, val) 功能&#xff1a;返回指向第一个不小于 val 的元素的迭代器。含义&#xff1a;如果…