TypeScript 5.2’s ‘using’ Keyword: Managing Resources with Ease

Simon Köck
3 min readJul 1, 2023

TypeScript has always been at the forefront of evolving JavaScript, offering developers a type-safe way to build scalable JavaScript applications. With TypeScript 5.2, a new keyword, using, makes its debut, bringing more finesse in managing resources like file handles and database connections.

A Peek into ‘using’

The using keyword is designed to manage anything that has a Symbol.dispose function and disposes of it when it leaves scope. This concept is rooted in the TC39 proposal which has reached Stage 3, indicating its potential future addition to JavaScript itself.

{
const getResource = () => {
return {
[Symbol.dispose]: () => {
console.log('Hooray!')
}
}
}

using resource = getResource();
} // 'Hooray!' logged to console

This keyword will prove extremely useful for managing resources, especially those that are bound by specific lifetimes or need to be closed or released after use, such as file handles or database connections.

The Role of Symbol.dispose

Symbol.dispose is a new global symbol in JavaScript that plays an integral role in the using keyword implementation. When a function is assigned to Symbol.dispose, the associated object is considered a "resource" — an object with a specific lifetime. This resource can then be managed using the using keyword.

Asynchronous Disposal with Symbol.asyncDispose and await using

But what about resources that need to be disposed of asynchronously? TypeScript 5.2 has got that covered too. You can use Symbol.asyncDispose and await using to manage resources that need asynchronous handling, such as when you want to ensure that a database connection is closed before the program continues.

const getResource = () => ({
[Symbol.asyncDispose]: async () => {
await someAsyncFunc();
},
});

{
await using resource = getResource();
}

Real-World Applications: File Handlers and Database Connections

The using keyword can greatly simplify resource management in several scenarios. Let's consider file handlers in Node.js. Traditionally, you would need to open the file and ensure it's closed in a finally block. With using, you can encapsulate the process in a function that returns an object with a Symbol.asyncDispose method, which is then automatically invoked when the scope ends.

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");
// Do stuff with file.filehandle
} // Automatically disposed

Similarly, managing database connections also becomes more streamlined with using. The connection is automatically closed when the scope ends, freeing you from manual cleanup and making the code more readable and less error-prone.

const getConnection = async () => {
const connection = await getDb();

return {
connection,
[Symbol.asyncDispose]: async () => {
await connection.close();
},
};
};

{
await using db = getConnection();
// Do stuff with db.connection
} // Automatically closed

Conclusion

The introduction of the using keyword in TypeScript 5.2 isa testament to the language's continuous evolution and its commitment to enhancing developer productivity. By providing a built-in mechanism for resource management, using reduces boilerplate, improves code readability, and helps prevent common bugs related to incorrect or forgotten resource disposal. As TypeScript continues to bring features from the future into the present, we eagerly look forward to what's next!

--

--

Simon Köck
Simon Köck

Written by Simon Köck

Simon Köck, an 19-year-old full stack developer from Austria, combines youthful energy with technical mastery for innovative web solutions.

No responses yet