Course
TypeScript
169 lessons across 14 modules
Beginner to advanced, assuming JavaScript fundamentals. Basic types, functions, interfaces, unions and narrowing, generics, classes, migrating existing JavaScript, tsconfig, React and Node.js, utility and conditional types, and the standards a team needs - ending in a full-stack project typed end to end. The road is laid out in full; lessons are being written one at a time.
TypeScript Fundamentals
What it adds to JavaScript, and what it costs
Prerequisite: the JavaScript course →What is TypeScript?
1JavaScript with a type system that is checked, then erased.
A .ts file and the .js it compiles to, side by side
Why TypeScript?
2Catching mistakes before they run, and editors that understand your code.
A typo in a property name caught before the page loads
JavaScript vs TypeScript
3What changes, what does not, and what the runtime never sees.
Why types cannot validate data that arrives over the network
TypeScript Advantages
4Refactoring, autocomplete, and documentation that cannot go stale.
Renaming a field across forty files with confidence
TypeScript Compiler
5tsc checks and emits - two jobs, separable.
A build that emits JavaScript despite type errors
Type Checking
6Structural typing - shape matters, names do not.
Two unrelated interfaces that are interchangeable
Type Inference
7The idea - the compiler working out types you did not write.
A whole function typed with a single annotation
Installing TypeScript
8Per project, not global, and pinned in the lockfile.
Two developers seeing different errors from different versions
First TypeScript Program
9Writing one, breaking it on purpose, and reading the error.
An error message read line by line
Compiling TypeScript
10tsc, watch mode, noEmit, and where the output goes.
Type-checking without emitting, the way most projects do
TypeScript with Node.js
11Running TypeScript on the server, compiled or directly.
tsx against tsc against Node type stripping
TypeScript with Vite
12Vite strips types and does not check them - so something else must.
A dev server running happily over a type error
Basic Types
The primitives, and the special types around them
String
13The string type, and the String wrapper you should never use.
string against String, and why one is wrong
Number
14One number type for integers and floats alike.
Why there is no int, and what that means for ids
Boolean
15true and false - and truthiness the type system does not track.
A boolean parameter that makes a call site unreadable
Null
16An intentional absence, and strictNullChecks making it visible.
The same code with the check off and on
Undefined
17Not set yet - and how it differs from null in practice.
An optional property against one set to undefined
Any
18Switching the checker off, and how far that spreads.
One any quietly disabling checks three functions away
Unknown
19Could be anything - so you must check before you use it.
A JSON.parse result that forces you to validate
Never
20The type with no values, and the exhaustiveness check it enables.
A switch that fails to compile when a case is added
Void
21A function that returns nothing useful.
A callback typed as void that may return a value
BigInt
22Integers beyond the safe range, and not mixing them with number.
A database id too large for a number
Symbol
23Unique values, and unique symbol for typed keys.
A private-by-convention key that cannot collide
Type Inference
24The rules - widening, contextual typing, and when inference gives up.
let x = "a" becoming string while const x = "a" stays "a"
Type Annotations
25Where to write types and where to leave them to inference.
Annotating boundaries, not every local variable
Literal Types
26A type that is exactly one value.
A direction that can only be "up" or "down"
Functions
Typing what goes in and what comes out
Function Type Annotations
27Annotating a function as a whole, not just its parts.
A typed function expression assigned to a variable
Parameter Types
28Why parameters must be annotated when little else must.
An unannotated parameter becoming implicit any
Return Types
29Inferred or declared - and why exported functions should declare.
A return type that changes silently after a refactor
Optional Parameters
30The question mark, and the undefined it adds to the type.
An optional parameter forcing a check in the body
Default Parameters
31Defaults that make a parameter optional and infer its type.
A default removing the need for an annotation
Rest Parameters
32Typing a variable number of arguments.
A logger accepting any number of messages
Function Types
33Describing a function as a type you can reuse.
One Handler type shared by twelve callbacks
Arrow Functions
34Typing arrows, including generic arrows.
An inline arrow that infers everything from context
Callback Functions
35Typing the functions you hand to someone else.
An array method callback typed with no annotation at all
Higher-Order Functions
36Functions that take or return functions, typed end to end.
A withRetry wrapper that keeps the original signature
Function Overloads
37Several signatures for one implementation - and when a union is simpler.
A parse function whose return type follows its input
Objects, Interfaces and Type Aliases
Describing the shape of your data
Object Type Annotations
38Inline object types, and when to give them a name.
An inline type repeated three times, then named once
Interfaces
39Naming a shape so it can be reused and extended.
A User interface used across a whole app
Optional Properties
40Properties that may be missing, and handling that honestly.
An optional email that every consumer must check
Readonly Properties
41Fields that cannot be reassigned - at the type level only.
A readonly id that the runtime still lets you change
Interface Methods
42Method syntax against property syntax, and the variance difference.
Two ways to write the same method, checked differently
Extending Interfaces
43Building one interface from another.
An AdminUser that is a User with permissions
Type Aliases
44Naming any type, not just object shapes.
A union, a tuple, and a function type, each named
Interface vs Type
45The real differences, and a rule you can follow without thinking.
Declaration merging - the one thing only interfaces do
Nested Objects
46Deep shapes, and splitting them into named parts.
A user with an address with coordinates
Index Signatures
47Objects used as dictionaries, and noUncheckedIndexedAccess.
A lookup that should have returned undefined in its type
Arrays, Tuples and Enums
Collections, fixed positions, and named constants
Typed Arrays
48Arrays whose elements all share a type.
A list of users that cannot accept a string
Array Type Syntax
49T[] against Array<T>, and when each reads better.
A union array that needs its brackets
Readonly Arrays
50Arrays that cannot be mutated through this reference.
A function that promises not to touch its input
Tuples
51Fixed length, a type per position.
A [latitude, longitude] pair
Named Tuples
52Labels on positions, for readability and editor hints.
A tuple that documents itself in the tooltip
Optional Tuple Elements
53Trailing positions that may be absent.
An RGB tuple with an optional alpha
Enums
54Named constants - and the fact that they emit runtime code.
An enum and the JavaScript object it becomes
Numeric Enums
55Auto-incrementing values, and the reverse mapping.
A numeric enum accepting a number it never defined
String Enums
56Readable values in logs and payloads.
A status that means something in a database row
Enum Alternatives
57Union types and as const objects - usually the better choice.
The same enum rewritten with no runtime cost
Union, Intersection and Advanced Types
Combining types, and narrowing them back down
Union Types
58A value that is one of several types.
An id that may be a string or a number
Intersection Types
59A value that is all of several types at once.
A timestamped entity built from two types
Literal Types
60Literal unions as the foundation that narrowing is built on.
A status union the compiler can reason about case by case
Type Narrowing
61The compiler tracking what a value must be after a check.
A union shrinking inside an if block
typeof
62Narrowing primitives with a runtime check.
Handling a string or number id
instanceof
63Narrowing class instances.
Telling a ValidationError from any other Error
in
64Narrowing by the presence of a property.
Separating a Cat from a Dog by what they have
Discriminated Unions
65A shared tag field that makes every case explicit.
loading, success, and error states in one type
Type Guards
66Checks the compiler understands and trusts.
A filter that narrows the array it returns
Custom Type Guards
67Writing value is Type, and the lie it lets you tell.
A guard that is wrong and a compiler that believes it
Nullable Types
68Handling null and undefined without drowning in checks.
Optional chaining and ?? narrowing as they go
Generics
Writing something once that keeps its caller types
What are Generics?
69Type parameters - a function over types, not just values.
An identity function that keeps what it was given
Generic Functions
70Declaring and inferring type parameters.
getFirst returning the element type, not unknown
Generic Interfaces
71Interfaces parameterised by the type they carry.
An ApiResponse<T> for every endpoint
Generic Types
72Type aliases with parameters.
A Result<T, E> used for every fallible call
Generic Classes
73Classes whose members depend on a type parameter.
A typed Cache<K, V>
Multiple Type Parameters
74Several parameters, and how they relate.
A map function from T to U
Generic Constraints
75Requiring a type parameter to have certain capabilities.
A function that needs its input to have an id
extends
76The constraint keyword, and keyof inside it.
A getProperty that only accepts real keys
Default Generic Types
77Type parameters that fall back when not supplied.
An event emitter that defaults to string events
Generic Utility Functions
78Small reusable helpers, typed precisely.
groupBy returning a correctly keyed record
Generic React Components
79Generics applied to a component, so its props follow its data.
A List<T> whose renderItem receives a T
Classes and OOP
Classes, modifiers, and inheritance, with types
Classes
80Class syntax with types, and fields declared up front.
A class that states its shape before its constructor
Constructors
81Typed constructor parameters, and definite assignment.
A field the compiler says is never initialised
Properties
82Declared fields, initialisers, and strictPropertyInitialization.
The ! that silences a real bug
Methods
83Typed methods, and this inside them.
A method that loses this when passed as a callback
Access Modifiers
84Controlling visibility - at compile time only.
A private field still visible in the compiled output
public
85The default, and when to write it anyway.
Parameter properties that need a modifier to exist
private
86TypeScript private against JavaScript #private.
Which one survives a cast and which one does not
protected
87Visible to subclasses, hidden from everyone else.
A base class hook meant for overriding
readonly
88Properties set once, in the constructor.
An id that cannot be reassigned after creation
Inheritance
89extends, super, and override - and preferring composition.
A hierarchy flattened into composed parts
Abstract Classes
90Base classes that cannot be instantiated, with required members.
A Repository with abstract find and save
Interfaces with Classes
91implements - a contract the class must satisfy.
Two storage classes behind one interface
Static Members
92Members on the class itself, not on instances.
A static factory method
Getters and Setters
93Accessors with types, and validation on assignment.
A setter rejecting a negative price
TypeScript with JavaScript
Adopting TypeScript in a codebase that already exists
Migrating JavaScript to TypeScript
94Why a big-bang rewrite fails, and what works instead.
A migration planned one directory at a time
.js vs .ts
95Mixing both in one project while you move.
A TypeScript file importing a JavaScript one
allowJs
96Letting the compiler include JavaScript files at all.
The first config change in any migration
checkJs
97Type-checking JavaScript without renaming a single file.
Errors appearing in plain .js files
JSDoc Types
98Types written as comments, fully checked.
A typed JavaScript file with no build step
Gradual Migration
99Loose settings first, tightening one flag at a time.
A migration tracked by error count going down
any Problems
100Escaping any during a migration without letting it spread.
Counting the anys, and making the number go down
unknown vs any
101Replacing any with unknown as the safe temporary type.
A migrated function that now forces a check
Handling Legacy JavaScript
102Declaration files for code you cannot change.
A .d.ts for an untyped internal library
TypeScript Migration Strategy
103The full plan - order, tooling, and knowing when you are done.
A migration playbook a team can follow
Modules and Configuration
Imports that erase cleanly, and tsconfig flag by flag
ES Modules
104How TypeScript resolves modules, and moduleResolution.
An import that works in the editor and fails at runtime
Import
105Importing values and types, and the extension question.
Why a .ts file imports "./user.js"
Export
106Exporting values and types from one module.
A barrel file, and what it costs
Default Export
107Default against named exports, from a types perspective.
A default export that renames freely and breaks search
Type-only Imports
108import type - guaranteed to erase, never to execute.
A circular import broken by making it type-only
Type-only Exports
109Re-exporting types without dragging values along.
verbatimModuleSyntax flagging a mixed export
tsconfig.json
110The project file - what it includes and what it controls.
Reading a real tsconfig and knowing the project
target
111Which JavaScript version is emitted, and what gets downlevelled.
The same async code at ES5 and at ES2022
module
112Which module system is emitted.
A package that must ship ESM and CommonJS
strict
113What the flag switches on - one flag, eight checks.
Listing every check strict enables
noImplicitAny
114Refusing to guess any when it cannot infer.
Every unannotated parameter surfacing at once
strictNullChecks
115Making null and undefined their own types.
The flag that finds the most real bugs
paths
116Import aliases - and why the runtime also needs to know.
An @/ alias that compiles and then fails to resolve
Project References
117Splitting one large project into incrementally built parts.
A monorepo that type-checks in seconds instead of minutes
TypeScript with React and Node.js
Typing both ends of a real application
The React course →Typing React Props
118Props interfaces, children, and defaults that type correctly.
A Button whose variant cannot be misspelled
Typing State
119useState inference, and the cases that need an annotation.
State that starts as null and becomes a user
Typing Events
120The React event types, and finding the right one quickly.
ChangeEvent, MouseEvent, and FormEvent in one form
Typing Forms
121One type for the form shape, driving state and handlers.
A field name that cannot be typed wrong
Typing useRef
122DOM refs against value refs, and the null you must handle.
Focusing an input without a non-null assertion
Typing useReducer
123A discriminated union of actions, checked exhaustively.
Adding an action and letting the compiler find every gap
Typing Custom Hooks
124Hooks that return tuples or objects with precise types.
A useToggle whose tuple stays a tuple
Generic Components
125The React-specific typing that makes a generic component pleasant.
A Table whose column keys come from its row type
API Response Types
126Types for data you did not produce, validated at the boundary.
A cast that lies against a schema that checks
TypeScript with Express
127A typed Express server, and where the types are weak.
A handler whose request body is any by default
Request Types
128Typing params, query, and body - and validating them.
A route whose params type matches its path
Response Types
129Constraining what a handler is allowed to send back.
A response that cannot leak a password field
Middleware Types
130Extending the request with what middleware adds.
req.user typed after the auth middleware runs
Service Layer Types
131Types at the seam between routes and business logic.
A service that knows nothing about Express
Database Types
132Row types, and generating them rather than writing them.
Types generated from the schema, never drifting from it
Advanced TypeScript
Utility types, and computing types from other types
Utility Types
133The built-in toolkit for deriving types - an overview.
One User type producing five related types
Partial
134Every property optional.
An update payload derived from the full type
Required
135Every property required.
A config type after defaults have been applied
Readonly
136Every property read-only - one level deep.
A frozen settings object
Pick
137Keeping a subset of properties.
A UserPreview holding only id and name
Omit
138Dropping properties - and the typo it will not catch.
A public user without its password hash
Record
139An object type from a key type and a value type.
A lookup keyed by a status union, with every key required
Exclude
140Removing members from a union.
Every status except "deleted"
Extract
141Keeping only the union members that match.
The events that carry a payload
NonNullable
142Removing null and undefined from a type.
A value after it has been validated
ReturnType
143The type a function returns, without restating it.
A type derived from a factory function
Parameters
144A function parameter list, as a tuple.
A wrapper forwarding exactly the same arguments
Awaited
145Unwrapping a promise, however deeply nested.
The resolved type of an async function
Conditional Types
146Types that choose between branches, and distribution over unions.
A type that is a string array for strings and a number otherwise
Mapped Types
147Transforming every property of a type.
Building Partial yourself to see how it works
Template Literal Types
148String types built from other string types.
Event names like "onClick" derived from "click"
infer
149Extracting a type from inside another in a conditional type.
Writing your own ReturnType
TypeScript Best Practices
Standards for a codebase more than one person works in
Avoiding Excessive any
150any as a review standard - where it is acceptable and where it is not.
A lint rule that makes each any a deliberate choice
unknown vs any
151unknown as the default for anything untrusted.
A team rule applied to every external input
Strict Mode
152Turning strict on in a codebase written without it.
Enabling one check at a time until strict is on
Type Naming Conventions
153Names that say what a type is, with no Hungarian prefixes.
Why IUser and UserType both read badly
Reusable Types
154Deriving rather than duplicating.
Three hand-written types replaced by one and two utilities
Domain Types
155Types that model the business, not the database.
Branded ids that cannot be mixed up
API Types
156Sharing types between client and server, and the risk in that.
One contract package used by both ends
DTO Types
157Transfer shapes kept apart from domain shapes.
A DTO mapped to a domain object at the boundary
Type Organization
158Where types live - colocated or shared, and the rule for choosing.
A types folder that became a dumping ground
Type-safe Error Handling
159catch gives you unknown - and Result types as an alternative.
A function whose errors appear in its signature
Type-safe Configuration
160Validating environment variables once, at startup.
A missing variable failing at boot rather than at 2am
TypeScript Code Review Guidelines
161What to look for in a pull request, as a checklist.
Reviewing a real diff against the list
TypeScript Project
A full-stack application, typed end to end
Project Setup and Architecture
162React, Express, and PostgreSQL in one strict TypeScript repo.
The folder structure and tsconfig agreed before any feature
Shared Types and DTOs
163The contract between client and server, defined once.
A change to the API breaking the build on both sides
Authentication
164Typed tokens, a typed request user, and protected routes.
req.user available and typed in every handler
Users, Roles, and Permissions
165Domain types, discriminated roles, and type guards on access.
A permission check the compiler can see
CRUD and API Integration
166Generic service functions and typed endpoints end to end.
One generic repository serving three resources
Validation
167Runtime validation that produces static types.
A schema that is also the TypeScript type
Error Handling
168Typed errors from database to UI.
A 409 conflict surfacing as a specific message in a form
Testing and Final Review
169Tests for the parts types cannot prove, and a strict-mode audit.
The finished app with zero any, reviewed against the plan