当前位置: 首页 > news >正文

带你看看 TypeScript 5.0 的新特性

一、写在前面

TypeScript 5.0 已经于 2023 年 3 月 16 日发布了,带来了许多新功能,同时也在性能方面进行了优化,下面让我们来一起看看新版 TypeScript 中比较有重要的变化吧。

二、新特性

2-1、速度、包体积优化

首先是新版本性能的提升,5.0 版本在构建速度、包体积方面都有着不错的优化,下面这张表格是 5.0 版本相对于 4.9 的性能提升幅度:

项目相对于 TS 4.9 的优化幅度
material-ui 构建时间90%
TypeScript 编译器启动时间89%
TypeScript 编译器自构建时间87%
Outlook Web 构建时间82%
VS Code 构建时间80%
npm 包大小59%

TypeScript 5.0 具体做了什么来优化性能呢?

  • 首先是将namespace迁移到module,这样可以应用更多现代构建工具的特性来进行优化(如作用域提升),并移除一些已弃用的代码,将包大小减少了约 26.4 MB。
  • 其次是 TS 精简了编译器内部的对象所存储的数据,减少了内存使用量。
  • 然后是在一些特定领域进行优化,如在闭包中偶尔使用var,而不是letconst来提高解析性能。

总的来说,大多数 TypeScript 项目都能从 TypeScript 5.0 中获得 10% 到 20% 性能提升。

2-2、新的装饰器标准

装饰器这个东西,写 ts 的小伙伴一定不会陌生,虽然它还不是一个标准的 js 特性,但 ts 已经在之前的版本就支持了“实验性”装饰器。而在最新的 5.0 版本中,装饰器语法将不再是一个“实验性”的语法,也不需要在编译选项中加入--experimentalDecorators配置项了(虽然在新版本,这个编译选项依旧会存在),TypeScript 5.0 将会原生支持装饰器语法!

下面让我们来看一个装饰器的例子吧——

首先我们有一个很简单的类:

class Person {name: string;constructor(name: string) {this.name = name;}greet() {console.log(`Hello, my name is ${this.name}.`);}
}const p = new Person("zy");
p.greet();

我们想在这个类的greet函数中加点日志,并记录调用函数的名称,那么最简单的方式是这样做:

class Person {name: string;constructor(name: string) {this.name = name;}greet() {console.log("LOG: Entering method greet.");console.log(`Hello, my name is ${this.name}.`);console.log("LOG: Exiting method greet.");}
}const p = new Person("zy");
p.greet();

但如果我们想给更多的函数都加上类似的功能,那用装饰器就非常合适了,比如我们可以编写一个loggedMethod,如下所示:

function loggedMethod(originalMethod: any,context: ClassMethodDecoratorContext
) {const methodName = String(context.name);function replacementMethod(this: any, ...args: any[]) {console.log(`LOG: Entering method '${methodName}'.`);const result = originalMethod.call(this, ...args);console.log(`LOG: Exiting method '${methodName}'.`);return result;}return replacementMethod;
}

这样我们用loggedMethod这个装饰器来装饰这个函数,就可以实现上述效果了:

class Person {name: string;constructor(name: string) {this.name = name;}@loggedMethodgreet() {console.log(`Hello, my name is ${this.name}.`);}
}const p = new Person("zy");
p.greet();// Output:
//
//   LOG: Entering method 'greet'.
//   Hello, my name is zy.
//   LOG: Exiting method 'greet'.

我们甚至可以创建一个“返回装饰器函数的函数”,这样我们就可以为装饰器开发更多定制化更多的功能,比如说,我想自定义输出到控制台的字符串的前缀:

function loggedMethod(headMessage = "LOG:") {return function actualDecorator(originalMethod: any,context: ClassMethodDecoratorContext) {const methodName = String(context.name);function replacementMethod(this: any, ...args: any[]) {console.log(`${headMessage} Entering method '${methodName}'.`);const result = originalMethod.call(this, ...args);console.log(`${headMessage} Exiting method '${methodName}'.`);return result;}return replacementMethod;};
}

这样我们在loggedMethod被用作装饰器之前调用它,就可以实现传入定制的字符串作为控制台输出字符串的前缀了:

class Person {name: string;constructor(name: string) {this.name = name;}@loggedMethod("LOG:")greet() {console.log(`Hello, my name is ${this.name}.`);}
}const p = new Person("zy");
p.greet();// Output:
//
//   LOG: Entering method 'greet'.
//   Hello, my name is zy.
//   LOG: Exiting method 'greet'.

2-3、const类型参数

在推断对象的类型时,ts 通常会选择一种通用的类型。例如,在这种情况下,会将names的类型推断为string []

type HasNames = { readonly names: string[] };
function getNamesExactly<T extends HasNames>(arg: T): T["names"] {return arg.names;
}// Inferred type: string[]
const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] });

推断成string []固然没有问题,但由于namesreadonly的,而推断出的类型不是readonly的,这就会产生一些困扰。虽然我们可以通过添加as const来解决这个问题,就像这样:

// The type we wanted:
//    readonly ["Alice", "Bob", "Eve"]
// The type we got:
//    string[]
const names1 = getNamesExactly({ names: ["Alice", "Bob", "Eve"] });// Correctly gets what we wanted:
//    readonly ["Alice", "Bob", "Eve"]
const names2 = getNamesExactly({ names: ["Alice", "Bob", "Eve"] } as const);

但这样写很麻烦,且容易被忘掉。所以在 TypeScript 5.0 中,我们可以将const修饰符直接添加到类型参数声明中,将常数类型推理变为默认值:

type HasNames = { names: readonly string[] };
function getNamesExactly<const T extends HasNames>(arg: T): T["names"] {
//                       ^^^^^return arg.names;
}// Inferred type: readonly ["Alice", "Bob", "Eve"]
// Note: Didn't need to write 'as const' here
const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] });

具体细节:https://github.com/microsoft/TypeScript/pull/51865

2-4、extends配置项支持多个配置文件

extends配置项支持多个配置文件其实是我个人认为 TypeScript 5.0 中最实用的一个特性了。当我们使用tsconfig.json管理多个项目时,很多情况下都会在一个“基准”配置文件上进行配置扩展,比如下面这样:

// packages/front-end/src/tsconfig.json
{"extends": "../../../tsconfig.base.json","compilerOptions": {"outDir": "../lib",// ...}
}

但是,在很多时候,我们会希望从多个配置文件进行扩展,但 TypeScript 4.9 及以前的版本都不支持这个功能!而好消息是,Typescript 5.0 现在允许该 extends 字段引入多个配置路径。例如,下面这种写法:

// tsconfig1.json
{"compilerOptions": {"strictNullChecks": true}
}// tsconfig2.json
{"compilerOptions": {"noImplicitAny": true}
}// tsconfig.json
{"extends": ["./tsconfig1.json", "./tsconfig2.json"],"files": ["./index.ts"]
}

在这个例子中,strictNullChecksnoImplicitAny都会在最终的tsconfig.json中生效。

注意,如果这些引入的配置文件中有字段冲突,那么后引入的字段会覆盖先引入的字段。

具体细节:https://github.com/microsoft/TypeScript/pull/50403

2-5、所有枚举变为联合枚举

TypeScript 最初在设计枚举类型时,只不过是将它们视为一组具有相同类型的数字常量,比如下面这个枚举E

enum E {Foo = 10,Bar = 20,
}

E.FooE.Bar相比于普通的变量,唯一特别之处在于它可以分配给任何类型为E的东西。除此之外,他们几乎和numbers类型没什么区别,就像下面这样:

function takeValue(e: E) {}takeValue(E.Foo); // works
takeValue(123); // error!

直到 TypeScript 2.0 引入了枚举文字类型,枚举才变得特殊。枚举文字类型为每个枚举成员提供了自己的类型,并将枚举本身变成了每个成员类型的集合。它们还允许我们仅引用枚举类型的一个子集,并缩小这些类型的范围,就如同下面展示的枚举Color

// Color is like a union of Red | Orange | Yellow | Green | Blue | Violet
enum Color {Red, Orange, Yellow, Green, Blue, /* Indigo */, Violet
}// Each enum member has its own type that we can refer to!
type PrimaryColor = Color.Red | Color.Green | Color.Blue;function isPrimaryColor(c: Color): c is PrimaryColor {// Narrowing literal types can catch bugs.// TypeScript will error here because// we'll end up comparing 'Color.Red' to 'Color.Green'.// We meant to use ||, but accidentally wrote &&.return c === Color.Red && c === Color.Green && c === Color.Blue;
}

而在某些场景——比如枚举成员使用函数调用初始化的时候,TypeScript 无法计算出枚举值的集合,它就会放弃联合枚举,转而使用旧的枚举策略。

而 TypeScript 5.0 解决了这个问题,它通过为每个枚举成员创建唯一类型,将所有枚举都变成联合枚举。这样,我们在所有情况下的枚举值,都将是联合枚举。

具体细节:https://github.com/microsoft/TypeScript/pull/50528

2-6、--moduleResolution配置项支持bundler选项

TypeScript 4.7 在--module--moduleResolution配置项中引入了node16nodenext选项。这些选项能更好地模拟 Node.js 中 ECMAScript 模块的查找规则。然而,这种模式有很多限制,例如,在 Node.js 的 ECMAScript 模块中,任何相对导入都需要包含文件扩展名:

// entry.mjs
import * as utils from "./utils"; //  wrong - we need to include the file extension.import * as utils from "./utils.mjs"; //  works

但随着前端技术的发展,这种查找规则已经落伍了。大多数现代打包工具在 Node.js 中使用 ECMAScript 模块和 CommonJS 模块查找规则的融合。所以为了模拟打包工具的工作方式,TypeScript 现在引入了一种新策略:--moduleResolution bundler.

{"compilerOptions": {"target": "esnext","moduleResolution": "bundler"}
}

如果你在使用像 Vite、esbuild、swc、Webpack、Parcel 等打包工具,那么bundler这个配置会非常合适。

具体细节:https://github.com/microsoft/TypeScript/pull/51669

2-7、支持export type *

在 TypeScript 3.8 引入类型导入/导出时,是不允许 export _ from "module"export _ as xx from "module" 这样的类型导出的。TypeScript 5.0 添加了对这两种类型导出语法的支持:

// models/vehicles.ts
export class Spaceship {// ...
}// models/index.ts
export type * as vehicles from "./vehicles";// main.ts
import { vehicles } from "./models";function takeASpaceship(s: vehicles.Spaceship) {//  ok - `vehicles` only used in a type position
}function makeASpaceship() {return new vehicles.Spaceship();//         ^^^^^^^^// 'vehicles' cannot be used as a value because it was exported using 'export type'.
}

详情请见:https://github.com/microsoft/TypeScript/pull/52217

相关文章:

带你看看 TypeScript 5.0 的新特性

一、写在前面 TypeScript 5.0 已经于 2023 年 3 月 16 日发布了&#xff0c;带来了许多新功能&#xff0c;同时也在性能方面进行了优化&#xff0c;下面让我们来一起看看新版 TypeScript 中比较有重要的变化吧。 二、新特性 2-1、速度、包体积优化 首先是新版本性能的提升&…...

C语言预处理条件语句的 与或运算

C语言预处理条件语句的 与或运算 1.#ifdef 与或运算 #ifdef (MIN) && (MAX) ----------------------------错误使用 #if defined(MIN) && defined(MAX) ---------------- 正确使用 #ifdef (MIN) || (MAX) -----------------------------错误使用 …...

从零实现深度学习框架——学习率调整策略介绍

引言 本着“凡我不能创造的,我就不能理解”的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导。 要深入理解深度学习,从零开始创建的经验非常重要,从自己可以理解的角度出发,尽量不使用外部完备的框架前提下,实现我…...

系统架构:经典三层架构

引言 经典三层架构是分层架构中最原始最典型的分层模式&#xff0c;其他分层架构都是其变种或扩展&#xff0c;例如阿里的四层架构模式和DDD领域驱动模型。阿里的 四层架构模型在三层基础上增加了 Manager 层&#xff0c;从而形成变种四层模型&#xff1b;DDD架构则在顶层用户…...

数据结构--二叉树

目录1.树概念及结构1.1数的概念1.2数的表示2.二叉树概念及结构2.1二叉树的概念2.2数据结构中的二叉树2.3特殊的二叉树2.4二叉树的存储结构2.4.1顺序存储2.4.2链式存储2.5二叉树的性质3.堆的概念及结构3.1堆的实现3.1.1堆的创建3.1.2堆的插入3.1.3堆顶的删除3.1.4堆的代码实现3.…...

Keil5安装和使用小记

随着keil版本的更新&#xff0c;一些使用问题一随之产生。本文针对安装目前最新版本keil软件和使用问题做一些总结。 目录1 Keil5下载&安装1.1 官网下载链接1.2 软件安装1.2.1 安装说明1.2.2 关于 51 和 ARM 共存的问题1.3 软件破解2 pack包安装 & 破解2.1 下载2.2 安装…...

多机器人集群网络通信协议分析

本文讨论的是多机器人网络通信各层的情况和协议。 每个机器人连接一个数据传输通信模块&#xff08;以下简称为数传&#xff0c;也泛指市面上的图传或图数一体的通信模块&#xff09;&#xff0c;数传之间进行组网来传递信息。 根据ISO的划分&#xff0c;网络通信的OSI模型分…...

【PyTorch】手把手带你快速搭建PyTorch神经网络

手把手带你快速搭建PyTorch神经网络1. 定义一个Class2. 使用上面定义的Class3. 执行正向传播过程4. 总结顺序相关资料话不多说&#xff0c;直接上代码1. 定义一个Class 如果要做一个神经网络模型&#xff0c;首先要定义一个Class&#xff0c;继承nn.Module&#xff0c;也就是i…...

【完整代码】用HTML/CSS制作一个美观的个人简介网页

【完整代码】用HTML/CSS制作一个美观的个人简介网页整体结构完整代码用HTML/CSS制作一个美观的个人简介网页——学习周记1HELLO&#xff01;大家好&#xff0c;由于《用HTML/CSS制作一个美观的个人简介网页》这篇笔记有幸被很多伙伴关注&#xff0c;于是特意去找了之前写的完整…...

Java分布式事务(九)

文章目录&#x1f525;XA强一致性分布式事务实战_Atomikos介绍&#x1f525;XA强一致性分布式事务实战_业务说明&#x1f525;XA强一致性分布式事务实战_项目搭建&#x1f525;XA强一致性分布式事务实战_多数据源实现&#x1f525;XA强一致性分布式事务实战_业务层实现&#x1…...

基于深度学习的动物识别系统(YOLOv5清新界面版,Python代码)

摘要&#xff1a;动物识别系统用于识别和统计常见动物数量&#xff0c;通过深度学习技术检测日常几种动物图像识别&#xff0c;支持图片、视频和摄像头画面等形式。在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数据集以及PyQt的UI界面。动物识别系统主要用于常…...

K8S集群之-ETCD集群监控

### 生产ETCD集群监控核心指标 etcd服务存活状态 ​ up{job~"kubernetes-etcd.*"}0 ​ 说明&#xff1a;up0代表服务挂掉 etcd是否有脱离情况 etcd_server_has_leader{job~"kubernetes-etcd.*"}0 说明&#xff1a;每个instance&#xff0c;该值应该都…...

一文弄懂熵、交叉熵和kl散度(相对熵)

一个系统中事件发生的概率越大&#xff0c;也就是其确定性越大&#xff0c;则其包含的信息量越少&#xff0c;可以认为一个事件的信息量就是该事件发生难度的度量&#xff0c;事件所包含的信息量越大则其发生的难度越大。并且相互独立的事件&#xff0c;信息量具有可加性。相互…...

10从零开始学Java之开发Java必备软件Intellij idea的安装配置与使用

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者前言壹哥在前面的文章中&#xff0c;带大家下载、安装、配置了Eclipse这个更好用的IDE开发工具&#xff0c;并教会了大家如何在Ecli…...

04 - 进程参数编程

---- 整理自狄泰软件唐佐林老师课程 查看所有文章链接&#xff1a;&#xff08;更新中&#xff09;Linux系统编程训练营 - 目录 文章目录1. 问题1.1 再论execve(...)1.2 main函数&#xff08;默认进程入口&#xff09;1.3 进程空间概要图1.4 编程实验&#xff1a;进程参数剖析1…...

【python进阶】你真的懂元组吗?不仅是“不可变的列表”

&#x1f4da;引言 &#x1f64b;‍♂️作者简介&#xff1a;生鱼同学&#xff0c;大数据科学与技术专业硕士在读&#x1f468;‍&#x1f393;&#xff0c;曾获得华为杯数学建模国家二等奖&#x1f3c6;&#xff0c;MathorCup 数学建模竞赛国家二等奖&#x1f3c5;&#xff0c…...

《C++ Primer Plus》(第6版)第13章编程练习

《C Primer Plus》&#xff08;第6版&#xff09;第13章编程练习《C Primer Plus》&#xff08;第6版&#xff09;第13章编程练习1. Cd类2. 使用动态内存分配重做练习13. baseDMA、lacksDMA、hasDMA类4. Port类和VintagePort类《C Primer Plus》&#xff08;第6版&#xff09;第…...

【多线程】多线程案例

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;Java EE初阶&#x1f447; ✨每日一语&#xff1a;we can not judge the value of a moment until it becomes a memory. 目 录&#x1f35d;一. 单例模式&#x1f364;1. 饿汉模式实现&#x1f9aa;2. 懒汉模…...

【IoT】嵌入式驱动开发:IIC子系统

IIC有三种接口实现方式 三种时序对比: 图1 IIC子系统组成 图2 图3 IIC操作流程 设备端 1.i2c_get_adapter 2.i2c_new_device(相当于register设备) 3.I2c_put_adapter 驱动端 1.填充i2c_driver 2.i2c_add_driver(相当于register驱动) 3.在probe中建立访问方式 client相…...

DJ2-4 进程同步(第一节课)

目录 2.4.1 进程同步的基本概念 1. 两种形式的制约关系 2. 临界资源&#xff08;critical resource&#xff09; 3. 生产者-消费者问题 4. 临界区&#xff08;critical section&#xff09; 5. 同步机制应遵循的规则 2.4.2 硬件同步机制 1. 关中断 2. Test-and-Set …...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...