BeginnerTypeScript · Lesson 7 of 7

Modules, Node.js Built-ins & npm Scripts

Split code across files, read files with node:fs and automate tasks with npm scripts.

As programs grow, split them into modules: each file exports what other files may use, and imports what it needs. Set "type": "module" in package.json to use modern ES modules in Node.js.

Node.js ships built-in modules for files (node:fs/promises), paths (node:path), operating-system info and more. The node: prefix makes it clear the import is built-in, not from npm.

Add scripts to package.json so everyone on the team runs the project the same way: npm run dev, npm run typecheck, npm start.

src/math.tsTypeScript
export function average(values: number[]): number {
  if (values.length === 0) return 0;
  return values.reduce((a, b) => a + b, 0) / values.length;
}

export const PASS_MARK = 30;
src/main.tsTypeScript
import { readFile, writeFile } from "node:fs/promises";
import { average, PASS_MARK } from "./math";

async function main(): Promise<void> {
  await writeFile("scores.txt", "78\n64\n25\n91\n");
  const text = await readFile("scores.txt", "utf8");
  const scores = text.split("\n").filter(Boolean).map(Number);

  console.log("Average:", average(scores).toFixed(1));
  console.log("Passed:", scores.filter((s) => s >= PASS_MARK).length);
}

main();
package.jsonJSON
{
  "name": "hello-ts",
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/main.ts",
    "typecheck": "tsc --noEmit",
    "start": "tsx src/main.ts"
  }
}

Key points

  • One responsibility per module; export only what others need.
  • Use node:-prefixed imports for Node.js built-ins.
  • npm scripts document and standardise how a project is run.

Exercise

Create src/text.ts exporting wordCount(text) and longestWord(text). In src/main.ts, read a .txt file with readFile and print both results. Add a count script to package.json that runs it.

Show solution

Try the exercise yourself first — then compare your approach with this one.

Put the text helpers in their own module and export them. main.ts imports them, reads the file with readFile, and prints the results. A count script in package.json runs it with one command.

src/text.tsTypeScript
export function wordCount(text: string): number {
  return text.split(/\s+/).filter(Boolean).length;
}

export function longestWord(text: string): string {
  return text
    .split(/\s+/)
    .filter(Boolean)
    .reduce((longest, word) => (word.length > longest.length ? word : longest), "");
}
src/main.tsTypeScript
import { readFile, writeFile } from "node:fs/promises";
import { longestWord, wordCount } from "./text";

async function main(): Promise<void> {
  await writeFile("essay.txt", "Photosynthesis happens in the chloroplasts of green plants.");
  const text = await readFile("essay.txt", "utf8");
  console.log("Words:", wordCount(text));          // Words: 8
  console.log("Longest:", longestWord(text));      // Longest: Photosynthesis
}

main();
package.jsonJSON
{
  "type": "module",
  "scripts": {
    "count": "tsx src/main.ts"
  }
}

Check your understanding

  1. What makes a value in one file available to other files?

  2. What does the node: prefix in import { readFile } from "node:fs/promises" indicate?

  3. What is the main benefit of npm scripts?

  4. Which package.json setting enables modern ES modules in Node.js?

Ask AI