A guided path for JavaScript and Node developers learning TypeScript.
Turn familiar JavaScript runtime code into safer, better-specified systems.
This track is for JavaScript and Node developers who already know the runtime and want safer refactors, clearer contracts, and better tooling through TypeScript. It focuses on annotations and inference, safer API shapes, boundary typing, typed tests, and practical migration strategy.
before you start
- $You already write real JavaScript/Node code. This path assumes professional instincts, not beginner-level programming lessons.
- $Expect comparison-first modules: each stop starts from familiar JavaScript/Node habits, then shows where TypeScript agrees or pushes back.
- $Plan to practice the target ecosystem directly — syntax, testing, and design choices should feel native by the end, not translated.
by the end you can
- →Read and write idiomatic TypeScript without translating every line back through JavaScript/Node.
- →Spot which JavaScript/Node instincts transfer cleanly and which ones need a different TypeScript mental model.
- →Use the six modules as a working checklist when you build your first real TypeScript tool, service, or feature.
syllabus
6 modules, one capstone.
Mindset shift
Reframe TypeScript as a way to describe and defend contracts in code that still runs as ordinary JavaScript.
Annotations and inference
Learn where TypeScript annotations help, where inference is already enough, and how generics and module surfaces sharpen existing JavaScript code.
Safer API shapes
Move from loose JavaScript objects toward explicit TypeScript models for handlers, payloads, and API results.
Boundary typing
Learn how TypeScript sharpens JavaScript error and input handling by forcing clearer assumptions at the edges.
Typed tests and mocks
Use TypeScript in tests to keep fixtures, mocks, and helper APIs honest without turning the suite into a type exercise.
Migration strategy
Adopt TypeScript incrementally in real JavaScript/Node codebases by typing boundaries and public APIs before chasing total coverage.
track reference
Keep the shared translation aids in one place.
These are track-wide lookup tables and task patterns, not lesson-specific reading. Use them when you need a quick reset on the recurring source-to-target language translations.
Data type mappings
Recheck the building blocks when a translation starts to wobble.
JavaScript/Node
string
TypeScript
string
Common operations
- Template literals and string helpers remain familiar.
- Type annotations matter most at function and module boundaries, not on every local string.
- Keep runtime validation separate from the compile-time type.
JavaScript/Node
array
TypeScript
array / T[]
Common operations
- Push and array pipelines remain familiar.
- Element types become explicit when the array crosses a public boundary.
- Use readonly arrays or generics when the contract needs to signal more than ordinary JS arrays do.
JavaScript/Node
object / null / undefined
TypeScript
typed object shape / union / null
Common operations
- Use interfaces or type aliases for real contracts.
- Model missing values and variants with unions instead of loose optional-field objects.
- Keep unknown at boundaries until data is proven safe.
Comparative cheat sheet
Keep the most common tasks visible while you practice.
| Task | JavaScript/Node | TypeScript |
|---|---|---|
| Define a public function contract | function greet(name) {
return `hello ${name}`;
} | function greet(name: string): string {
return `hello ${name}`;
} |
| Type an object boundary | function loadUser(user) {
return user.name;
} | type User = { name: string };
function loadUser(user: User): string {
return user.name;
} |
| Handle unknown input safely | function readName(body) {
return body.name.trim();
} | function readName(body: unknown): string {
if (typeof body !== 'object' || body === null || !("name" in body) || typeof body.name !== 'string') {
throw new Error('invalid name');
}
return body.name.trim();
} |
| Model missing values honestly | if (!user) { return null; } | if (user === null) {
return null;
} |
| Type a test helper | const makeUser = (overrides = {}) => ({ id: '1', name: 'Ana', ...overrides }); | type User = { id: string; name: string };
const makeUser = (overrides: Partial<User> = {}): User => ({ id: '1', name: 'Ana', ...overrides }); |
capstone
Ship a small TypeScript project that proves the mental model stuck.
Build one focused artifact in TypeScript using the same comparison-first habits from the track: start from a familiar JavaScript/Node shape, then deliberately redesign it the way TypeScript expects.
- ●Translate a familiar JavaScript/Node data flow into idiomatic TypeScript structure instead of preserving the old shape by force.
- ●Apply the early modules to data modeling, control flow, and API boundaries before you add tooling, polish, or deployment concerns.
- ●Use the later modules to verify, test, and package the result the way TypeScript developers expect to see it shipped.
ready?
Start with module 01 — Mindset shift.