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, 新特性的普及需要一定的时间和验证。

相关推荐
四岁半儿1 小时前
常用css
前端·css
你的人类朋友2 小时前
说说git的变基
前端·git·后端
姑苏洛言2 小时前
网页作品惊艳亮相!这个浪浪山小妖怪网站太治愈了!
前端
阿杆2 小时前
玩转 Amazon ElastiCache 免费套餐:小白也能上手
后端
字节逆旅2 小时前
nvm 安装pnpm的异常解决
前端·npm
Jerry2 小时前
Compose 从 View 系统迁移
前端
阿杆2 小时前
无服务器每日自动推送 B 站热门视频
后端
GIS之路2 小时前
2025年 两院院士 增选有效候选人名单公布
前端
四岁半儿2 小时前
vue,H5车牌弹框定制键盘包括新能源车牌
前端·vue.js
烛阴3 小时前
告别繁琐的类型注解:TypeScript 类型推断完全指南
前端·javascript·typescript