TypeScript 5.2 新特性显示资源管理 Symbol.dispose 和 using 关键字

一、安装最新版的 TypeScript

ts 复制代码
cd your_dir
pnpm init
pnpm add typescript # 当前的 ts 版本是 `5.2.2`

当然可以使用最新的 bun/deno 等运行时直接支持 typescript>

二、提案

📕ECMAScript 显示资源管理 一个在对象上执行显式资源清理的方法。由using声明和DisposableStack对象的语义调用。

三、初始化

sh 复制代码
npx tsc --init

由于 TS 需要编译成 JS 才能运行,在各大 javascript 运行时中。

四、修改配置

json 复制代码
{
  "compilerOptions": {
     "lib": ["ES2015", "DOM", "ESNext"],
  }
}

在 lib 中至少 ES2015ESNext,因为 Symbol.dispose 目前还处在 lib.esnext.dispable.d.ts 中。

五、Symbol.dispose 定义方法

ts 复制代码
{
  const getResource = () => {
    return {
      [Symbol.dispose]: () => {
        console.log('Hello World!')
      }
    }
  }
} 

🎡 Symbol.dispose 在浏览中已经能够使用。

六、Symbol.asyncDispose 定义异步方法

ts 复制代码
const getResource = () => ({
  [Symbol.asyncDispose]: async () => {
    await someAsyncFunc();
  },
});
{
  await using resource = getResource();
}

七、using 使用方法

using 是一个关键字,与 var/let/const 类似,在 c# 中也有类似的关键字 设计

ts 复制代码
{
  const getResource = () => {
    return {
      [Symbol.dispose]: () => {
        console.log('Hello World!')
      }
    }
  }
  using resource = getResource();
} 

八、作用

  • 数据库链接关闭
  • 文件句柄
  • 订阅关闭

九、替换 try-finally

ts 复制代码
import { open } from "node:fs/promises";
let filehandle;
try {
  filehandle = await open("thefile.txt", "r");
} finally {
  await filehandle?.close();
}
ts 复制代码
import { open } from "node:fs/promises";

const getFileHandle = async (path: string) => {
  const filehandle = await open(path, "r");
  return {
    filehandle,
    [Symbol.asyncDispose]: async () => {
      await filehandle.close();
    },
  };
};
{
  await using file = getFileHandle("thefile.txt"); // 离开此作用域之后自动调用 close
}

getFileHandle 函数打开文件,getFileHandle 且返回了 [Symbol.asyncDispose], 配合 using 关键使用,解决了 try-finally 层级的代码。代码的创建与销毁的逻辑放在了 getFileHandle 函数内部,更加符合函数时编程的范式。

十、在类中使用

  • 全局的 DisposableAsyncDisposable 异步版本。
ts 复制代码
class MyResouse implements Disposable {
  #name = 'a';
  #path = '/';
  constructor(name: string, path: string) {
    this.#name = name;
    this.#path = path;
  }

  clear(name, path) {
    // your clear logic
  }

  [Symbol.dispose]() {
    this.clear(this.#name, this.#path)
  }
}
  • 使用
ts 复制代码
 {
    using file = new TempFile("lucy", "/list/lucky");

    // use file...

    if (someCondition()) {
        // do some more work...
        return;
    }
}

十一、DisposableStack/AsyncDisposableStack

ts 复制代码
function doSomeWork() {
    const path = ".some_temp_file";
    const file = fs.openSync(path, "w+");

    using cleanup = new DisposableStack();
    cleanup.defer(() => {
        fs.closeSync(file);
        fs.unlinkSync(path);
    });

    // use file...

    if (someCondition()) {
        // do some more work...
        return;
    }

    // ...
}

在这里,该defer()方法只接受一个回调,并且该回调将在cleanup被处理后运行。这样做的好处是不在需要函数的返回值了。

十二、错误处理

ts 复制代码
class ErrorA extends Error {
    name = "ErrorA";
}
class ErrorB extends Error {
    name = "ErrorB";
}

function throwy(id: string) {
    return {
        [Symbol.dispose]() {
            throw new ErrorA(`Error from ${id}`);
        }
    };
}

function func() {
    using a = throwy("a");
    throw new ErrorB("oops!")
}

try {
    func();
}
catch (e: any) {
    console.log(e.name); // SuppressedError
    console.log(e.message); // An error was suppressed during disposal.

    console.log(e.error.name); // ErrorA
    console.log(e.error.message); // Error from a

    console.log(e.suppressed.name); // ErrorB
    console.log(e.suppressed.message); // oops!
}

using声明应该能够应对异常;如果抛出错误,则在处理后重新抛出。另一方面,函数体可能会按预期执行,但Symbol.dispose可能会抛出异常。在这种情况下,该异常也会被重新抛出。

但是,如果处理之前和处理期间的逻辑都抛出错误,会发生什么情况?对于这些情况,SuppressedError已作为 的新子类型引入Error。它具有一个保存suppressed最后抛出的错误的属性和一个保存error最近抛出的错误的属性。

🦀using 声明及相关更加详细的用法

十三、小结

本文主要讲解了 using 新特性 显示资源管理,在浏览中 Symbol.dispose 已经可以使用,但是在 node.js 等环境中依然不同使用,包含 using, 新特性的普及需要一定的时间和验证。

相关推荐
我叫汪枫17 小时前
前端物理引擎库推荐 - 让你的网页动起来!
前端
钢门狂鸭19 小时前
关于rust的crates.io
开发语言·后端·rust
脑子慢且灵21 小时前
[JavaWeb]模拟一个简易的Tomcat服务(Servlet注解)
java·后端·servlet·tomcat·intellij-idea·web
华仔啊1 天前
SpringBoot 中 6 种数据脱敏方案,第 5 种太强了,支持深度递归!
java·后端
雾恋1 天前
最近一年的感悟
前端·javascript·程序员
A黄俊辉A1 天前
axios+ts封装
开发语言·前端·javascript
小李小李不讲道理1 天前
「Ant Design 组件库探索」四:Input组件
前端·javascript·react.js
连合机器人1 天前
晨曦中的守望者:当科技为景区赋予温度
java·前端·科技
郑板桥301 天前
tua-body-scroll-lock踩坑记录
前端·javascript
勇敢牛牛_1 天前
使用Rust实现服务配置/注册中心
开发语言·后端·rust·注册中心·配置中心