@types/node — Typing the Node.js Runtime
`@types/node` provides TypeScript definitions for Node.js built-in modules — `fs`, `path`, `http`, `process`, `Buffer`, `EventEmitter`, and more. It also types the global `process.env`. Because Node.js and browser APIs overlap but differ, keeping `lib` set to `ES2022` (no `dom`) in your backend tsconfig prevents cross-runtime type leaks.
@types/node — Core Node.js API Types
# npm install --save-dev @types/node
// ── File system — strongly typed ──────────────────────────────
import fs from "node:fs/promises";
import path from "node:path";
async function readConfig(filename: string): Promise<unknown> {
const filePath: string = path.join(process.cwd(), "config", filename);
const raw: string = await fs.readFile(filePath, "utf-8");
return JSON.parse(raw); // returns unknown — validate before use
}
async function writeOutput(name: string, data: unknown): Promise<void> {
const outPath = path.resolve("dist", `${name}.json`);
await fs.mkdir(path.dirname(outPath), { recursive: true });
await fs.writeFile(outPath, JSON.stringify(data, null, 2), "utf-8");
}
// ── process.env — typed with declaration merging ──────────────
// src/types/environment.d.ts:
declare global {
namespace NodeJS {
interface ProcessEnv {
NODE_ENV: "development" | "test" | "production";
PORT?: string; // optional — may not be set
DATABASE_URL: string;
JWT_SECRET: string;
REDIS_URL?: string;
}
}
}
export {}; // module augmentation requires this
// Now: process.env.NODE_ENV is "development" | "test" | "production"
// And: process.env.TYPO is a compile error — unknown env var caught!
// ── Node vs Browser runtime difference ───────────────────────
// Node tsconfig must NOT include "dom" in lib:
// "lib": ["ES2022"] ← correct for Node
// "lib": ["ES2022", "DOM"] ← WRONG — adds window, document, etc.
// ── Buffer — Node-specific type ───────────────────────────────
const buf: Buffer = Buffer.from("hello", "utf8");
const hex: string = buf.toString("hex");
const arr: Uint8Array = buf; // Buffer extends Uint8Array
// ── EventEmitter — typed events ───────────────────────────────
import { EventEmitter } from "node:events";
class TaskEmitter extends EventEmitter {
emitCreated(task: Task): boolean {
return this.emit("task-created", task);
}
onCreated(listener: (task: Task) => void): this {
return this.on("task-created", listener);
}
}
// ── Worker threads, streams, crypto — all typed ───────────────
import { createHash } from "node:crypto";
import { Readable } from "node:stream";
function hashContent(content: string): string {
return createHash("sha256").update(content).digest("hex");
}Common Mistakes
- Adding `dom` lib to Node.js tsconfig — this lets Node code call `document.getElementById()` without a compile error, then crash at runtime. Keep backend and frontend tsconfigs strictly separate.
- Using `process.env.FOO` without null checking — even with typed ProcessEnv, `PORT?: string` means it might be undefined. Always use `process.env.PORT ?? '3000'` or validate with Zod at startup.
- Not using `node:` prefix — modern Node.js recommends `import fs from 'node:fs'` to explicitly mark built-ins and avoid any chance of npm package shadowing.
Tip
Tip
Practice typesnode Typing the Nodejs Runtime in small, isolated examples before integrating into larger projects. Breaking concepts into small experiments builds genuine understanding faster than reading alone.
Node is single-threaded for JS but uses multiple threads for I/O
Practice Task
Note
Practice Task — (1) Write a working example of typesnode Typing the Nodejs Runtime from scratch without looking at notes. (2) Modify it to handle an edge case (empty input, null value, or error state). (3) Share your solution in the Priygop community for feedback.
Quick Quiz
Common Mistake
Warning
A common mistake with typesnode Typing the Nodejs Runtime is skipping edge case testing — empty inputs, null values, and unexpected data types. Always validate boundary conditions to write robust, production-ready typescript code.
Key Takeaways
- `@types/node` provides TypeScript definitions for Node.
- Adding `dom` lib to Node.js tsconfig — this lets Node code call `document.getElementById()` without a compile error, then crash at runtime. Keep backend and frontend tsconfigs strictly separate.
- Using `process.env.FOO` without null checking — even with typed ProcessEnv, `PORT?: string` means it might be undefined. Always use `process.env.PORT ?? '3000'` or validate with Zod at startup.
- Not using `node:` prefix — modern Node.js recommends `import fs from 'node:fs'` to explicitly mark built-ins and avoid any chance of npm package shadowing.