dev/notes

Spot a mistake? Highlight any text in a post and click Report — it goes straight to the author.

intermediate · TypeScript · August 17, 2026 · 2 min read

How to Set Up a TypeScript Project from Scratch

Create a TypeScript project from scratch: tsconfig.json, strict mode, and build scripts. A hands-on setup guide for Node.js and TypeScript.

Why strict mode from day one

TypeScript’s value is catching mistakes before runtime — but only if strict is on. Turning it on later means fixing a wall of errors at once. Enable it now, when there’s no legacy code to migrate.

Step 1 — Initialize the project

mkdir my-ts-project && cd my-ts-project
npm init -y
npm install -D typescript tsx @types/node
  • typescript — the compiler.
  • tsx — runs .ts files directly during development.
  • @types/node — types for Node’s standard library.

Step 2 — Create tsconfig.json

npx tsc --init

Replace the generated file with a focused config:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}

noUncheckedIndexedAccess makes array/object access return T | undefined, forcing you to handle missing keys explicitly.

Step 3 — Write your first module

src/index.ts:

interface Greeting {
  name: string;
  punctuation?: string;
}

export function greet(input: Greeting): string {
  const mark = input.punctuation ?? "!";
  return `Hello, ${input.name}${mark}`;
}

console.log(greet({ name: "devnotes" }));

Step 4 — Add build and dev scripts

In package.json:

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

npm run dev hot-reloads during development; npm run build typechecks and emits plain JavaScript to dist/.

Step 5 — Wire typechecking into CI

Make type errors fail the build:

npm run build

tsc with strict is your first line of defense — treat any error as a bug, not a suggestion.

Troubleshooting

  • Cannot find module with ESM — with "module": "NodeNext", local imports need explicit .js extensions (import { greet } from "./index.js").
  • Object is possibly undefined — that’s strict/noUncheckedIndexedAccess doing its job; narrow with a guard or optional chaining.
  • Output directory is messy — confirm rootDir/outDir are set so tsc mirrors your src/ layout.

Summary

You have a strict, modern TypeScript project with a dev loop (tsx watch) and a production build (tsc). The compiler is now guarding every commit.

Related posts

Comments

One comment per thread every 30 minutes · edits are unlimited.