Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TypeScript

Overview

TypeScript is a typed superset of JavaScript developed by Microsoft (lead architect Anders Hejlsberg, first released 2012). It adds a static type system on top of JavaScript: you write .ts files with type annotations, and the TypeScript compiler (tsc) type-checks and erases the types, emitting plain JavaScript that runs anywhere JS runs.

“TypeScript is JavaScript with syntax for types.” — TypeScript Handbook

TypeScript does not change how the code runs — types are compile-time only. Its value: earlier error detection, self-documenting code, safer refactoring, and editor tooling (autocomplete, go-to-definition) powered by the type checker.

Why TypeScript Matters

  • Dominant in the ecosystem: React, Next.js, Angular, NestJS, and most major libraries ship types or are written in TS.
  • Enterprise adoption: large codebases stay maintainable; teams rename/refactor with confidence.
  • The “superset” guarantee: any valid JS is valid TS (with allowJs/checkJs, plain JS files are checked too).
  • Compiler performance story: the Go-native rewrite (TypeScript 7, GA July 2026) makes full builds ~8–12× faster (10.6 s vs 125.7 s for VS Code’s codebase), removing the “too slow for big repos” objection.

The Type System

Primitives and basics

let count: number = 5;
const name: string = "Ada";
let isDone: boolean = false;
let anything: any = "whatever";        // opt-out of checking — avoid
let maybe: unknown = JSON.parse(x);    // safe unknown — must narrow before use
let nothing: void = undefined;
let n: null = null;
let u: undefined = undefined;

Structural typing (the key idea)

TypeScript is structurally typed: two types are compatible if their shapes match, not because of a shared name/class hierarchy. This mirrors how JavaScript actually works (duck typing) while adding safety.

interface Point { x: number; y: number; }
function draw(p: Point) { /* ... */ }

// Any object with x and y is a Point — no class relationship needed
draw({ x: 0, y: 0 });
const other = { x: 1, y: 2, z: 3 };  // extra properties OK (variable, not literal)
draw(other);

This differs fundamentally from nominal typing (Java/C#) — the interview-relevant distinction.

Interfaces vs type aliases

interfacetype
Declaration merging✅ (can extend)
Primitives/unions/tuples
Mapped/conditional types
When to useObject shapes, library API contractsUnions, tuples, complex transformations

Modern guidance: prefer interface for object shapes you expect to extend; type for everything else.

Literal types and unions

type Direction = "north" | "south" | "east" | "west";   // string literal union
type Status = "idle" | "loading" | "success" | "error";
type Result = { ok: true; data: string } | { ok: false; error: Error };  // discriminated union

Discriminated unions (a common kind/type discriminant field) are the backbone of modeling state machines, API responses, and Redux actions.

Generics

function identity<T>(arg: T): T { return arg; }

interface Box<T> { value: T; }
const b: Box<number> = { value: 42 };

// Constraints
function longest<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b;
}

Generics capture relationships between types (input type → output type) rather than fixing a concrete type. Interview topics: generic constraints, default type params, keyof, and conditional types.

Advanced Types (interview gold)

type Keys = keyof { a: 1, b: 2 };            // "a" | "b"
type Readonly<T> = { readonly [P in keyof T]: T[P] };  // mapped type
type Partial<T> = { [P in keyof T]?: T[P] };
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type Exclude<T, U> = T extends U ? never : T;  // conditional type
type Return<T> = T extends (...args: any[]) => infer R ? R : never;  // infer

Utility types built into the stdlib: Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract, NonNullable, Parameters, ReturnType, Awaited.

Narrowing — TypeScript narrows unions through checks:

function format(value: string | number) {
  if (typeof value === "string") return value.toUpperCase();   // narrowed to string
  return value.toFixed(2);                                     // narrowed to number
}

typeof, instanceof, in, discriminated-union checks, and type predicates (value is T) all narrow.

tsconfig.json Essentials

OptionMeaning
strict: trueMaster switch: strictNullChecks, noImplicitAny, strictFunctionTypes, etc.
targetJS version emitted (ES2022, ES2023, …)
moduleModule system (commonjs, esnext, nodenext)
moduleResolutionHow imports resolve (bundler, node16, nodenext)
outDir / rootDirEmit layout
noEmitType-check only (common in CI and with bundlers)
declarationEmit .d.ts type declarations for library consumers
isolatedModulesSafe for single-file transpilers (esbuild, Babel, SWC)

strict mode is the default recommendation — it’s where TypeScript’s value lives (strictNullChecks alone catches a huge class of bugs).

Runtime: How Types Are Removed

Modern pipelines rarely run tsc for transpilation alone:

ToolRole
tscType-check + emit (the reference implementation)
esbuild / SWCBlazing-fast type-stripping transpilers (no type-check) — used by Vite, Next.js, tsup
ts-node / tsxRun TS directly in Node (tsx uses esbuild)
BabelTranspile via @babel/preset-typescript

TypeScript 5.8+/Node 22+ also supports type stripping natively (--experimental-strip-types), and Node 24 has stable type-stripping support — meaning many .ts files run in Node with zero build step. (Type checking still requires tsc.)

TypeScript vs JavaScript (interview framing)

AspectJavaScriptTypeScript
TypesDynamic, checked at runtimeStatic, checked at compile time
RuntimeRuns directlyTypes erased → runs as JS
ErrorsSurface at runtimeMany caught before runtime
ToolingLimited by dynamic typesRich (refactor, autocomplete)
Learning curveLowerHigher (type system)

Interview Questions

Q: What is structural typing and how does it differ from nominal typing?

Structural typing (TypeScript, Go, OCaml’s structural aspects) checks compatibility by shape: an object is a Point if it has the same members, regardless of class hierarchy. Nominal typing (Java, C#, Rust) requires an explicit name/type relationship (inheritance or interface implementation). TypeScript chose structural typing because JavaScript is duck-typed — the type system models the actual runtime behavior.

Q: What is the difference between interface and type?

interface supports declaration merging and is intended for object shapes and extensible API contracts. type aliases can express unions, tuples, primitives, and mapped/conditional types that interfaces cannot. Both are structural. Prefer interface for shapes, type for transformations/unions.

Q: How do discriminated unions help model state?

A discriminated union is a union of object types distinguished by a shared literal field (e.g., kind). With a switch (or if) on that field, TypeScript narrows each case to the specific variant — so the compiler guarantees you handle every case and the properties you access exist. This models async states (idle | loading | success | error), API results, and UI events safely.

Q: What did the TypeScript 7 rewrite change?

TypeScript 7 (GA July 2026) replaced the JavaScript-based compiler with a native Go port — a port, not a rewrite, preserving behavior — giving ~8–12× faster full builds via native code and shared-memory parallelism. It is the same tsc, same output, same strict-mode defaults (with some 6.0 deprecations becoming hard errors); the stable programmatic API for tooling lands in 7.1.

Q: How do you type an API response that could be an error?

Use a discriminated union:

type ApiResult<T> =
  | { ok: true; data: T }
  | { ok: false; status: number; message: string };

async function fetchUser(id: number): Promise<ApiResult<User>> { /* ... */ }

const res = await fetchUser(1);
if (res.ok) console.log(res.data.name);   // narrowed — safe
else console.error(res.status, res.message);

References

  • TypeScript Handbook — https://www.typescriptlang.org/docs/
  • TypeScript GitHub — https://github.com/microsoft/TypeScript
  • TypeScript blog: A 10x Faster TypeScript (native port announcement, March 2025) — https://devblogs.microsoft.com/typescript/a-10x-faster-typescript/
  • TypeScript blog: TypeScript 7 (GA, July 2026) — https://devblogs.microsoft.com/typescript/
  • tsconfig reference — https://www.typescriptlang.org/tsconfig/
  • JavaScript Overview — the language TypeScript supersets
  • V8 Engine — how the emitted JS runs
  • Node.js — running TypeScript server-side
  • React — TS is the default for React apps
  • FastAPI — Pydantic (Python) shares the “annotations → validation” idea
  • OCaml — strong static type systems beyond the JS world