Introduction to TypeScript
Types, interfaces, unions, generics and setting up tsc — JavaScript that catches bugs before you run it.
TypeScript is JavaScript with static types. You describe what kind of values your variables, parameters and objects hold, and the TypeScript checker finds mistakes — typos, missing properties, undefined values, wrong argument types — as you type, before the code ever runs. It's now the default for most professional JavaScript projects, including React apps.
Every JavaScript program is (almost) valid TypeScript, so you can adopt it gradually.
Why types?#
Types also power editor features: accurate autocomplete, go-to-definition, safe renaming, and inline documentation.
Setting up#
Write hello.ts:
There are three common ways to run it:
Node's built-in support only removes types — it doesn't check them — so keep tsc --noEmit in your workflow (or rely on your editor). In front-end projects, Vite handles .ts/.tsx files for you, and npm create vite@latest offers TypeScript templates. TypeScript 7 rewrote the compiler in Go, making type-checking roughly ten times faster than before.
Basic types#
Type inference
You rarely need to write types for variables — TypeScript infers them from the value:
A good rule: annotate function parameters and public APIs; let inference handle the rest.
Functions#
? marks optional parameters; void means "returns nothing useful".
Object types: type and interface#
interface and type are interchangeable for object shapes. Interfaces can be extended and merged; type can also name unions and other combinations. Pick one style per codebase — many teams use type for everything except public library APIs.
Union types and narrowing#
A union means "one of these types":
TypeScript narrows a union inside if blocks using typeof, Array.isArray, in, instanceof and equality checks.
Discriminated unions
Give each variant a common literal property and TypeScript can tell them apart — perfect for modelling states:
This makes impossible states (like "loading and has an error") impossible to write.
null, undefined and strict mode#
With "strict": true (the default from tsc --init), null and undefined must be handled explicitly:
This single check prevents the most common JavaScript runtime error: Cannot read properties of undefined.
any vs unknown#
any switches the checker off and spreads silently. Use unknown for values you haven't validated yet. For real apps, a validation library such as Zod or Valibot checks API data at runtime and gives you the TypeScript type.
Generics#
Generics are type parameters — they let a function or type work with many types while keeping them connected:
You use generics constantly without noticing: Array<string>, Promise<User>, Map<string, number>, React's useState<User | null>(null).
Handy utility types#
Also useful: ReturnType<typeof fn>, Parameters<typeof fn>, Awaited<T>, NonNullable<T>, and as const for literal types:
Classes in TypeScript#
(Parameter properties like public readonly owner generate code, so they're rejected by the erasableSyntaxOnly setting that Node's type stripping requires. Write a normal field plus constructor assignment if you run .ts files with Node directly.)
Typing the DOM#
TypeScript knows every DOM API:
querySelector returns Element | null, so TypeScript makes you handle the "not found" case.
Adding TypeScript to a JavaScript project#
- Install TypeScript and create a
tsconfig.jsonwith"allowJs": true. - Optionally add
// @ts-checkto the top of.jsfiles — TypeScript checks them using inference and JSDoc comments. - Rename files from
.jsto.tsone at a time, fixing errors as you go. - Install types for libraries that don't ship their own:
npm i -D @types/node.
Common mistakes#
- Using
anyto make errors go away. Useunknownand narrow, or fix the type. - Overusing
ascasts and the!non-null assertion — they're promises to the compiler that it can't verify. - Assuming types validate data at runtime — API responses can still be anything. Validate external data.
- Annotating everything. Let inference work; annotate boundaries (function parameters, exports).
- Turning off
strict— you lose the most valuable checks.
What's next#
Finally, bring everything together with performance and best practices: writing JavaScript that's fast, readable and maintainable.
Check your understanding
Quick quiz
1.When does TypeScript report type errors?
2.Given
function len(x: string | string[]) { ... }, how can you safely call a string-only method onx?3.Why prefer
unknownoveranyfor data of uncertain shape (e.g.JSON.parseresults)?
Finished reading?
Mark this lesson complete to track your progress.