Getting Started with TypeScript: A Practical Guide
TypeScript adds a safety net to JavaScript without slowing you down. Here's how to set it up, the handful of concepts that matter, and how to adopt it gradually.
TypeScript is JavaScript with types. You write almost the same code, add a few annotations, and the compiler catches a whole class of bugs before your code ever runs. Here’s the practical path to using it.
Why bother
Most runtime errors in JavaScript come down to a value not being what you assumed — undefined where you expected an object, a string where you expected a number. TypeScript surfaces those mistakes in your editor as you type, and it powers the autocomplete that makes large codebases navigable.
Setting it up
In any Node project:
npm install -D typescript
npx tsc --init
tsc --init creates a tsconfig.json. The one setting worth turning on immediately is strict:
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "ESNext"
}
}
Strict mode is where TypeScript earns its keep — it forces you to handle the null/undefined cases that cause most crashes.
The concepts that matter
Basic annotations
let count: number = 0;
function greet(name: string): string {
return `Hello, ${name}`;
}
In practice you rarely annotate variables — TypeScript infers them. You mostly annotate function parameters and object shapes.
Interfaces and types
Describe the shape of your data once and reuse it everywhere:
interface User {
id: number;
name: string;
email?: string; // optional
}
Unions
A value that can be one of several types:
type Status = "loading" | "success" | "error";
Unions plus strict mode give you exhaustive checks — the compiler warns you if you forget to handle a case.
Adopt it gradually
You don’t have to convert everything at once. TypeScript runs on plain JavaScript, so you can:
- Rename one file from
.jsto.ts. - Fix the errors it surfaces.
- Repeat.
Set "allowJs": true so typed and untyped files coexist while you migrate.
Type narrowing: the everyday superpower
TypeScript follows your control flow. Inside an if that checks a value, the type is automatically narrowed:
function format(value: string | number) {
if (typeof value === "number") {
return value.toFixed(2); // value is `number` here
}
return value.trim(); // value is `string` here
}
This is why unions feel effortless in practice — you rarely cast types by hand; you check them, and the compiler narrows for you.
Common beginner mistakes
- Reaching for
any.anyswitches off type checking for that value and quietly spreads. Preferunknownand narrow it, or write the real type. - Over-annotating. Let inference do its job. Annotate function parameters and public APIs; leave local variables alone.
- Fighting third-party types. Most popular packages ship types or have a
@types/<name>package. Install those instead of declaring your own. - Ignoring
strictNullChecks. It’s the single most valuable check — leaving it off throws away most of TypeScript’s safety.
Frequently asked questions
Do I need to compile TypeScript myself?
Usually not. Bundlers and frameworks (Vite, Astro, Next.js) handle it. tsc is mainly for type-checking in CI and building libraries.
Is TypeScript slower at runtime? No. Types are erased during compilation — the JavaScript that ships is the same. The cost is at build time, not in the browser.
Should a brand-new project start with TypeScript? For anything beyond a throwaway script, yes. Adding types later is more work than starting with them.
The takeaway
Turn on strict, annotate your function boundaries, and let inference handle the rest. Within a week the editor feedback alone will make it hard to go back.
Keep reading
Takina · · 4 min read Structural Typing vs Nominal Typing in TypeScript
Structural typing checks shape, not name — TypeScript treats two differently-named types as compatible if their members match, unlike nominal systems.
Takina · · 5 min read TypeScript Variance Explained
Variance decides when TypeScript accepts Array<Dog> where Array<Animal> is expected — covariant, contravariant, or invariant, explained with examples.
Takina · · 5 min read Zod vs Yup: TypeScript Schema Validation Compared
Zod infers static TypeScript types directly from its schemas; Yup was built for JavaScript form validation first. How the two approaches differ.