TypeScript – Using Disposable
前言
TypeScript v5.2 多了一个新功能叫 Disposable。
Dispose 的作用是让 "对象" 离开 "作用域" 后做出一些 "释放资源" 的操作。
很多地方都可以看到 Dispose 概念。比如 Web Component 的 disconnectedCallback,Angular 组件的 ngOnDestroy。
而对象释放资源在其它面向对象语言中也很常见,比如 C# 的 Dispose Pattern。
所以这一次 TypeScript 只是推出了一个本来就该有的功能而已。
之所以这么迟才推出,是因为这个功能可以用其它方式替代(虽然不够优雅),而且 Dispose 在后端比较需要,前端现在都迷函数式,对象反而越来越少见了。
参考
YouTube – NEW Way To Create Variables In JavaScript
Docs – Announcing TypeScript 5.2
TypeScript 5.2's New Keyword: 'using'
目前的支持度
Disposable 并不是 TypeSCript 语法,而是 JavaScript ECMA 标准。目前在 stage 3。
当然 TypeScript 会做 down-level 处理,target ES2017 也可以使用,只是需要添加两句 runtime polyfill 就可以了。
在我写着一篇时,Prettier、ESLint、esbuild 都还不支持 Disposable。要测试只能用 TypeScript Compiler (AKA tsc)。
Prettier Issue, esbuild issue 视乎还没人去提。
搭建环境
用 tsc 搭建环境,不会的可以看这篇。
在 tsconfig.json 加入 compilerOptions.lib "ESNext.Disposable"
{
"compilerOptions": {
"target": "ES2017",
"lib": ["ES2017", "ESNext.Disposable", "DOM"]
}
}
我测试时完整的 tsconfig.json 如下

{
"compilerOptions": {
"target": "es2017",
"lib": [
"DOM",
"DOM.Iterable",
"ES2017",
"ES2019.Array",
"ES2019.Object",
"ESNext.Disposable"
],
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"useDefineForClassFields": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
/* Others */
"skipLibCheck": true,
"sourceMap": true,
}
}
然后加上 runtime polyfill
(Symbol as { dispose: symbol }).dispose ??= Symbol("Symbol.dispose");
(Symbol as { asyncDispose: symbol }).asyncDispose ??= Symbol("Symbol.asyncDispose");
注: 我这里只是做了一个轻量版,严格来说需要添加更多的 polyfill 的。
详情参考这篇:

没有 Disposable 怎么释放资源?
首先有个对象
class Person {
private intervalNumber: number;
constructor() {
this.intervalNumber = setInterval(() => console.log('call'), 1000);
}
dispose() {
clearInterval(this.intervalNumber);
}
}
对象用到了一个全局资源 setInterval,并曝露了一个接口释放该资源。
使用的情况下是这样的。
document.addEventListener('click', () => {
const person = new Person();
// do something...
person.dispose();
});
这样写不够安全,因为如果 do something 不小心报错,就会导致 dispose 没有被执行。于是
document.addEventListener('click', () => {
const person = new Person();
try {
// do something...
} catch {
console.log('error');
} finally {
person.dispose();
}
});
繁琐了很多,但是还可以接受,毕竟需要错误处理嘛。但是...如果我们不需要错误处理呢?
document.addEventListener('click', () => {
const person = new Person();
// do something...
if (Math.random() > 0.5) return;
person.dispose();
});
即便没有错误,只是 return 也会导致 dispose 没有执行。这个时候硬硬加 try finally 就有点过分了。
所以我们需要 Disposable 来优化,让代码变得优雅。
有 Disposable 怎样释放资源?
首先修改我们的 Person class。
class Person implements Disposable {
private intervalNumber: number;
constructor() {
this.intervalNumber = setInterval(() => console.log('call'), 1000);
}
[Symbol.dispose] {
clearInterval(this.intervalNumber);
}
}
原本的 dispose 方法变成了 [Symbol.dispose] 方法。还有 class 多了一个 implements Disposable
对象属性名配 Symbol 这个 pattern 是 JavaScript 一路以来的玩法。Iterator 也是这个玩法。
使用的情况下是这样的。
document.addEventListener("click", () => {
using person = new Person();
// do something...
if (Math.random() > 0.5) return;
});
person 前面把 const 改成了新的语法 "using"。然后...就没有然后了。
我们甚至都不需要调用 dispose。它自己会调用。
dispose 被调用的时机

using 在哪一个作用域,当那个作用域完结的时候,dispose 就会被调用。
上面例子中,我刻意加了一个花括弧作为 using 的 scope。所以触发的顺序是 1, 2, 3。
注意: JS 管理作用域的写法和 C# 不同哦。
下面是依据 C# 的写法。结果和上面的顺序是不相同的哦。不要搞错哦。

asyncDispose
如果释放资源是一个异步过程,那需要使用 asyncDispose
下面几个地方换成 async 就可以了。

然后调用时也加上 async 就可以了。

Downlevel Emit
参考: Github – Support using and await using declarations
using 会被 transpile 成 try finally。所以即使我们 target ES2017 也是可以使用 Displosable 功能的哦。
TypeScript – Using Disposable的更多相关文章
- 使用TypeScript拓展你自己的VS Code!
0x00 前言 在前几天的美国纽约,微软举行了Connect(); //2015大会.通过这次大会,我们可以很高兴的看到微软的确变得更加开放也更加务实了.当然,会上放出了不少新产品和新功能,其中就包括 ...
- 转载:《TypeScript 中文入门教程》 10、混入
版权 文章转载自:https://github.com/zhongsp 建议您直接跳转到上面的网址查看最新版本. 介绍 除了传统的面向对象继承方式,还流行一种通过可重用组件创建类的方式,就是联合另一个 ...
- Typescript Mixins(混合)
除了惯例的面对对象的思想,另一种较流行的通过可复用组件创建类的方法是将简单的类混合到一起.你可能对这种混合的方式比较熟悉或对Scala语言的特性有理解,这种模式在JavaScript社区也有一定的人气 ...
- [TypeScript] Understanding Generics with RxJS
Libraries such as RxJS use generics heavily in their definition files to describe how types flow thr ...
- 使用TypeScript拓展你自己的VSCode
转自:http://www.iplaysoft.com/brackets.html使用TypeScript拓展你自己的VSCode! 0x00 前言在前几天的美国纽约,微软举行了Connect(); ...
- TypeScript: Angular 2 的秘密武器(译)
本文整理自Dan Wahlin在ng-conf上的talk.原视频地址: https://www.youtube.com/watch?v=e3djIqAGqZo 开场白 开场白主要分为三部分: 感谢了 ...
- TypeScript为Zepto编写LazyLoad插件
平时项目中使用的全部是jQuery框架,但是对于做webapp来说jQuery太过于庞大,当然你可以选择jQuery 2.*针对移动端的版本. 这里我采用移动端使用率比较多的zepto框架,他跟jqu ...
- TypeScript Vs2013 下提示Can not compile modules unless '--module' flag is provided
VS在开发TypeScript程序时候,如果import了模块有的时候会有如下提示: 这种情况下,只需要对当前TypeScript项目生成设置为AMD规范即可!
- TypeScript
TypeScript: Angular 2 的秘密武器(译) 本文整理自Dan Wahlin在ng-conf上的talk.原视频地址: https://www.youtube.com/watch? ...
- 打造TypeScript的Visual Studio Code开发环境
打造TypeScript的Visual Studio Code开发环境 本文转自:https://zhuanlan.zhihu.com/p/21611724 作者: 2gua TypeScript是由 ...
随机推荐
- CM3调试系统简析
CM3 调试系统简析 **"一直以来,单片机的调试一直不是很突出的主题,很多简单些的程序在开发中,甚至都没有调试的概念,而只是把生成的映像直接烧入片子,再根据错误症状来判断问题,然后修改程序 ...
- Pycharm中开发vue element项目时eslint的安装和使用
在PyCharm中使用ESLint对Element UI进行语法检查和代码风格检查的配置步骤如下: 确保你的项目已经配置了ESLint并且可以正常运行.如果尚未安装ESLint,请先使用npm(或者你 ...
- el-config-provider
el-config-provider是Element Plus库中的一个组件,用于提供全局的配置.它是Element Plus在2.0版本中引入的新组件. el-config-provider组件的作 ...
- [oeasy]python0070_动态类型_静态类型_编译_运行_匈牙利命名法
动态类型_静态类型 回忆上次内容 上次了解了 帮助文档的 生成 开头的三引号注释 可以生成 帮助文档 文档 可以写成网页 python3 本身 也有 在线的帮助手册 目前的程序 提高了 可 ...
- 几个适合Java开发者的免费IDEA插件
今天,给大家推荐几个好用且免费的IntelliJ IDEA插件.如果你还没有用过,可以尝试一下,也许对你的日常工作会有一定的效率提升噢! RestFulTool 如果你是一个RESTful服务的开发者 ...
- 学习 React 需要具备的 JavaScript 知识
学习 React 需要具备的 JavaScript 知识 为什么要学习 React? React 可以与任何其他库或框架无缝集成,因为 React 是一个仅视图库(它是 Model View C on ...
- Python用shp文件裁剪多个遥感影像的方法
本文介绍基于Python中ArcPy模块,基于矢量数据范围,对大量栅格遥感影像加以批量裁剪掩膜的方法. 首先,话不多说,本文所需要的代码如下所示. # -*- coding: utf-8 -* ...
- nginx灰度发布、网站限速和防盗链
一.灰度发布(金丝雀发布) 灰度发布时使用比较平稳的过渡方式升级或者替换产品项目的方法统称 主要作用 及时发现项目问题 尽早获取用户反馈的信息,以改进产品 如果项目产生问题,可以将问题影响控制到最小范 ...
- PKUWC2024游记
PKUWC2024 游记 day -???? 得知今年冬令营在育才,非常高兴不用出远门了. day 1 当天上午 7:00 起来,然后做车去报道,非常堵车.感觉育才环境挺好的,~不像某人在读学校一样. ...
- Vue cil路由如何回到初始状态
前景:我们在网页里进入路由的地址后,会发现地址栏中会加上我们的路由地址,这样我就知道当前在哪个位置.但是这样子我们如何手动刷新浏览器,想要浏览器回到根路径的话,是无法直接回去的,因为地址没有更改.再怎 ...