Introduction to working with the file system in TypeScript
Working with the file system is one of the key tasks when developing server applications, utilities, and command-line tools. TypeScript, being a superset of JavaScript, provides all the capabilities of Node.js for interacting with files and directories, but adds strict typing, which makes the code more reliable and predictable.
In this article, we will take a detailed look at how to work with the file system in TypeScript: from basic read and write operations to advanced techniques such as working with streams and asynchronous processing. All examples are accompanied by ready-made code that you can immediately use in your projects.
To work with the file system in TypeScript, the built-in fs (file system) module from Node.js is used. It provides both synchronous and asynchronous methods. In modern projects, it is recommended to use asynchronous versions with promises (fs.promises) for non-blocking execution.
1. Project setup and module imports
Before starting, make sure your project is configured to work with Node.js and TypeScript. Create a project directory and initialize it:
mkdir fs-typescript-tutorialcd fs-typescript-tutorialnpm init -ynpm install typescript @types/node --save-devnpx tsc --initAfter setup, in the tsconfig.json file, make sure the module parameter is set to commonjs or ESNext, and target is set to ES2020 or higher.
Now let's create a file index.ts and import the necessary modules:
import * as fs from 'fs';import * as path from 'path';
// Or use the promises versionimport { promises as fsPromises } from 'fs';The path module is also important: it provides utilities for working with file paths, making the code cross-platform (Windows vs Unix).
2. Reading and writing files
2.1 Reading a file
Let's look at basic file operations. Let's start with reading the contents of a file. The asynchronous approach using async/await is the most modern and convenient way.
import { promises as fs } from 'fs';
async function readFileExample(filePath: string): Promise<string> { try { const data = await fs.readFile(filePath, 'utf-8'); return data; } catch (error) { console.error('Error reading file:', error); throw error; }}
// Usageasync function main() { const content = await readFileExample('./example.txt'); console.log('File contents:', content);}
main();The readFile method takes the path to the file and an optional encoding (default is null — returns a Buffer). If you specify 'utf-8', it will return a string.
2.2 Writing to a file
Writing data to a file is done using writeFile. If the file does not exist, it will be created. If it exists, it will be overwritten.
import { promises as fs } from 'fs';
async function writeFileExample(filePath: string, data: string): Promise<void> { try { await fs.writeFile(filePath, data, 'utf-8'); console.log('File successfully written'); } catch (error) { console.error('Error writing file:', error); throw error; }}
// Appending to the end of a file (append)async function appendFileExample(filePath: string, data: string): Promise<void> { try { await fs.appendFile(filePath, data + '', 'utf-8'); console.log('Data appended to the end of the file'); } catch (error) { console.error('Error appending data:', error); throw error; }}2.3 Working with JSON files
Often in applications, it is required to save and load data in JSON format. Here is a convenient wrapper: