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

相关推荐
踩着两条虫12 小时前
如何评价VTJ.PRO?
前端·架构·ai编程
GetcharZp12 小时前
告别 jq 噩梦!这款 JSON 神器 fx 让你在终端体验“丝滑”的数据操作
后端
Mh13 小时前
鼠标跟随倾斜动效
前端·css·vue.js
小码哥_常13 小时前
告别臃肿!Elasticsearch平替Manticore登场
后端
小码哥_常14 小时前
Kotlin类型魔法:Any、Unit、Nothing 深度探秘
前端
苍何15 小时前
万字保姆级教程:Hermes+Kimi K2.6 打造7x24h Agent军团
后端
我叫黑大帅15 小时前
为什么map查找时间复杂度是O(1)?
后端·算法·面试
Web极客码15 小时前
深入了解WordPress网站访客意图
服务器·前端·wordpress
幺风15 小时前
Claude Code 源码分析 — Tool/MCP/Skill 可扩展工具系统
前端·javascript·ai编程
vjmap15 小时前
唯杰地图CAD图层加高性能特效扩展包发布
前端·gis