TypeScript Basics
TypeScript adds static types to JavaScript, catching errors at compile time and dramatically improving the editor experience (autocomplete, inline docs, safe refactoring). Because it's a superset of JavaScript, you can adopt it gradually — rename a file, add a few types, and tighten over time.
This is the practical fundamentals reference: the types and constructs you'll use every day. For the powerful stuff (conditional/mapped types, narrowing tricks), see TypeScript Advanced Features.
TL;DR
- TypeScript is a superset of JavaScript with optional static typing.
- Start with basic types; enable
strictand tighten gradually. - Use interfaces/type aliases for shapes and generics for reusable code.
- Avoid
any; preferunknown+ narrowing.
Quick Example
A typed function catches mistakes the editor flags before you run anything:
Getting Started
Basic Types
Interfaces & Type Aliases
Interface vs type: use interface for object shapes (extendable, mergeable, clearer errors); use type for unions, intersections, tuples, and primitives. Pick a convention and stay consistent.
Functions
Generics
Write reusable, type-safe code that works over any type:
Classes
Access modifiers: public (default), private, protected, and readonly.
Type Guards & Narrowing
Utility Types
Enums & Modules
💡 Many teams prefer string-literal unions (
type Status = "pending" | "approved") overenum— they're simpler, have no runtime cost, and narrow cleanly.
Best Practices
- Turn on
strictmode and keep it on. - Avoid
any— preferunknownand narrow; type third-party data at the boundary. - Let inference work; annotate function signatures and public APIs, not every local.
- Validate external data at runtime (types vanish after compilation) — see Forms & Validation.
Common Mistakes
Reaching for any
Overusing the non-null assertion
FAQ
How do I adopt TypeScript in an existing project?
Gradually. Add TypeScript, allow JS files (allowJs), and rename files to .ts/.tsx one at a time, adding types as you go. Start with looser settings and progressively enable strict checks. Because TS is a superset, valid JS is valid TS to begin with.
Interface or type alias?
Use interface for object shapes — it's extendable, supports declaration merging, and gives clearer errors. Use type for unions, intersections, tuples, and primitive aliases. They overlap a lot; consistency matters more than the choice.
What's the difference between any and unknown?
any disables type checking entirely — anything goes, and errors slip through. unknown is the type-safe counterpart: you can hold any value but must narrow it (with typeof, a guard, etc.) before using it. Prefer unknown for untyped input.
Do TypeScript types exist at runtime?
No — types are erased during compilation, leaving plain JavaScript. That's why a value as User assertion isn't a runtime check, and why you must validate external input (API responses, forms) with a runtime schema library.
Should I use enums?
You can, but many teams prefer string-literal unions ("a" | "b") — they're simpler, have zero runtime footprint, and narrow well. Reserve enum for cases where you specifically want a named runtime object, and consider const enum to avoid generated code.
Related Topics
- TypeScript — The hub page
- TypeScript Advanced Features — Conditional/mapped types, narrowing
- JavaScript — The language underneath
- React — Heavily TypeScript-based
- Code Quality — Type checking in CI