using
Deklaracja zasobu, który zostanie automatycznie zwolniony przy wyjściu z bloku, nawet po błędzie.
Przykład
#// Polyfill: potrzebny tylko tam, gdzie brakuje wbudowanego Symbol.dispose
(Symbol as { dispose?: symbol }).dispose ??= Symbol('Symbol.dispose')
class DbConnection implements Disposable {
constructor(private name: string) {
console.log(`Otwieram ${name}`)
}
query(sql: string) {
console.log(`${this.name}: ${sql}`)
}
[Symbol.dispose]() {
console.log(`Zamykam ${this.name}`)
}
}
function saveProgress() {
using db = new DbConnection('progress-db')
db.query('UPDATE progress SET exp = exp + 20')
console.log('Koniec funkcji')
}
saveProgress()Otwieram progress-db progress-db: UPDATE progress SET exp = exp + 20 Koniec funkcji Zamykam progress-db
Definicja i zastosowanie
#Deklaracja using działa jak const, ale dodatkowo sprząta po sobie. Gdy program opuszcza blok z taką deklaracją, niezależnie od tego, czy dotrze do jego końca, wyjdzie przez return, czy przez wyjątek, wywoływana jest metoda [Symbol.dispose]() przechowywanego obiektu. W ten sposób zamkniesz połączenie z bazą, plik albo blokadę bez ręcznego pisania try...finally.
Obiekt nadaje się do using, jeśli ma metodę [Symbol.dispose](), czyli spełnia interfejs Disposable. Wartości null i undefined są dozwolone i zostają pominięte. Kilka zasobów w jednym bloku zwalnianych jest w kolejności odwrotnej do utworzenia. Wersja await using czeka na asynchroniczne sprzątanie w metodzie [Symbol.asyncDispose]() i działa tam, gdzie wolno użyć await.
TypeScript obsługuje tę składnię od wersji 5.2. W lib potrzebne są typy esnext.disposable (albo całe esnext). Przy target niższym niż ESNext kompilator zamienia using na kod pomocniczy, który korzysta z Symbol.dispose. Node.js 22 ma ten symbol wbudowany, ale nie każde środowisko go zna, dlatego pierwszy przykład zaczyna się od jednolinijkowego polyfilla.
Składnia
#using zasob = utworzZasob()
await using polaczenie = await polacz()
class Zasob implements Disposable {
[Symbol.dispose]() { … }
}Więcej przykładów
#function lock(name: string): Disposable {
console.log(`+ ${name}`)
return { [Symbol.dispose]: () => console.log(`- ${name}`) }
}
function gradeExam() {
using sheet = lock('arkusz')
using results = lock('wyniki')
throw new Error('brak odpowiedzi')
}
try {
gradeExam()
} catch (error) {
console.log((error as Error).message)
}+ arkusz + wyniki - wyniki - arkusz brak odpowiedzi
// await using korzysta z Symbol.asyncDispose, więc i on dostaje polyfill
(Symbol as { asyncDispose?: symbol }).asyncDispose ??= Symbol('Symbol.asyncDispose')
async function connect(name: string): Promise<AsyncDisposable> {
console.log(`Łączę z ${name}`)
return {
async [Symbol.asyncDispose]() {
console.log(`Rozłączam ${name}`)
}
}
}
async function syncProgress() {
await using api = await connect('progress-api')
console.log('Wysyłam postęp')
}
await syncProgress()
console.log('Gotowe')Łączę z progress-api Wysyłam postęp Rozłączam progress-api Gotowe
Dobre praktyki
#- Błąd „Symbol.dispose is not defined” w działającym programie oznacza, że środowisko nie zna jeszcze tego symbolu. Polyfill z pierwszego przykładu umieść na samym początku programu, przed definicjami klas, które go używają.
- Zmiennej z
usingnie można nadpisać. Próba przypisania kończy się błędem „Cannot assign to 'db' because it is a constant”. - Jeśli zasób jest potrzebny tylko przez chwilę, otwórz dla niego osobny blok
{ … }. Zostanie zwolniony przy klamrze zamykającej, a nie dopiero na końcu funkcji.
Powiązane hasła
#- implementsDeklaracja, że klasa spełnia kontrakt opisany interfejsem.
- interfaceNazwany opis kształtu obiektu, który można rozszerzać i łączyć.
- "lib"Wybiera wbudowane typy środowiska: wersję JavaScriptu, API przeglądarki i pojedyncze nowości języka.
- "target"Wersja JavaScriptu, do której kompilator zamienia kod.
Widzisz błąd albo brakuje przykładu? Napisz do nas.