TypeScript 5.2の新機能たち
usingとかDisposableとか
日々の作業で出てきた技術メモの切れ端を置いておくページ
usingとかDisposableとか
https://devblogs.microsoft.com/typescript/announcing-typescript-5-2-beta/
全部まとめたかったけど気になるやつだけ。
コードは全て上記ページから引用。
usingという宣言が追加されたimport * as fs from "fs";
export function doSomeWork() {
const path = ".some_temp_file";
const file = fs.openSync(path, "w+");
// use file...
// Close the file and delete it.
fs.closeSync(file);
fs.unlinkSync(path);
}こんな処理がある
一時ファイルを作って何かして、処理の最後で一時ファイルを閉じて、削除する。
export function doSomeWork() {
const path = ".some_temp_file";
const file = fs.openSync(path, "w+");
// use file...
if (someCondition()) {
// do some more work...
// Close the file and delete it.
fs.closeSync(file);
fs.unlinkSync(path);
return;
}
// Close the file and delete it.
fs.closeSync(file);
fs.unlinkSync(path);
}Early returnすると同じ処理を2回書く必要がある。try/catchで囲んでfinallyで行えば一度で済むがあまり見通しは良くない。
そこでTS5.2では新たに Symbol.disposeというのが追加された。 Symbol.disposeという名前のメソッドを実装しその中でクリーンアップ処理行う。( Symbol.disposeを実装するインタフェースである Disposableも追加されている)
class TempFile implements Disposable {
#path: string;
#handle: number;
constructor(path: string) {
this.#path = path;
this.#handle = fs.openSync(path, "w+");
}
// other methods
[Symbol.dispose]() {
// Close the file and delete it.
fs.closeSync(this.#handle);
fs.unlinkSync(this.#path);
}
}そしてこのクラスを使うときに新たに追加された usingメソッドを使う
export function doSomeWork() {
using file = new TempFile(".some_temp_file");
// use file...
if (someCondition()) {
// do some more work...
return;
}
}すると doSomeWorkを抜けたところで自動的に Symbol.disposeが実行される
Disposableなクラスを実装するまでもない場合には DisposableStackというのが使える。
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;
}
// ...
}DisposableStackのインスタンスを作り、deferメソッドの引数にクリーンアップ処理を渡していくと同じくスコープを抜けたときに実行してくれる。
Symbol.asyncDispose AsyncDisposable AsyncDisposableStackというのも用意されている// ✅ fine - no labels
type Pair1<T> = [T, T];
// ✅ fine - all fully labeled
type Pair2<T> = [first: T, second: T];
// ❌ previously an error
type Pair3<T> = [first: T, T];
// ~
// Tuple members must all have names
// or all not have names.declare let array: number[] | string[]
array.filter(x => !!x)上記のコードがTS5.2より前ではエラーになり、TS5.2では通るようになった。
filterやfindなどのメソッドのシグネチャは
filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[];こうなっているので従来Tの型が確定できなかったが、TS5.2ではこういったケースの時に (number | string)[]として扱ってくれるようになる。(配列型・タプル型のみ)
これによってチェックが通るようになる。
この場合返り値の型も (number | string)[]となってしまう点に注意
(個人的にはこのケースで困った試しがあまりないが……)