Section 1: Introduction to TypeScript
- Welcome to the Course
- How to Follow This Course?
- How to Remember Everything We Learn?
- Prerequisites for Learning TypeScript
- What is TypeScript & How does it Work?
- History of TypeScript
Section 2: TypeScript Fundamentals and Compiler Configuration
- What Are Types?
- Compiling TypeScript to JavaScript
- Configuring the TypeScript Compiler
- Strict Mode in TypeScript
- Debugging TypeScript Applications
- Including and Excluding Files in TypeScript
- Initializing a TypeScript Project Using the Init Command
- Statically vs Dynamically Typed Languages
- Strongly vs Weakly Typed Languages
- Top and Bottom Types in TypeScript
Section 3: Arrays and Tuples in TypeScript
- Array Typing in TypeScript
- Array Methods in TypeScript
- What Are Tuples?
- Readonly Arrays and Tuples
Section 4: Type Aliases, Literal Types, and Type Assertions
- What Are Type Aliases?
- Understanding Literal Types
- Template Literal Types
- Type Assertions in TypeScript
- Non-null Assertion in TypeScript
- Definite Assignment Assertion in TypeScript
Section 5: Objects & Functions Typing in Depth
- Object Literal Types
- Interfaces in TypeScript
- Types vs Interfaces
- Benchmarking Types and Interfaces
- Module Detection in TypeScript
- Why Do We Need Declaration Merging?
- Object Types from JavaScript
- Function Typing in TypeScript
- Creating Reusable Function Types
- Method Typing in Objects
- Optional Parameters in Functions and Methods
- Typing Rest Parameters in TypeScript
- Structural vs Nominal Typing
Section 6: Demystifying Unions and Intersections Using Set Theory
- Introduction to Set Theory
- Union and Intersection in Set Theory
- Value-Based and Property-Based Sets
- Union and Intersection in Property-Based Sets
- Types as Sets of JavaScript Values
- Union and Intersection in TypeScript
- Understanding Object Types in Depth
- Union and Intersection of Objects
- Union and Intersection with Conflicting Property Types
- Union and Intersection of Arrays
- The Research Behind Types as Sets: From Intuition to Proof
- Installing TypeScript Version 7.0
Section 7: Mastering Generics in TypeScript
- Introduction to Generics
- Creating Generic Interfaces
- Generic Functions in TypeScript
- Different Ways to Create Generic Functions
- Multiple Parameters in Generics
- Practical Use of Generic Functions
- Default Params in Generics
- Adding Constraints to Generics
- Generic Methods in TypeScript
- Working with Nested Generics
- Recursive Generics in TypeScript
- Built-in Generics in TypeScript
-
Understanding
Promise<T> in TypeScript
- Function Overloading in TypeScript
-
Understanding
const Modifier in Type Parameters
Section 8: Type-Level Programming in TypeScript
- Introduction to Type-Level Programming
- Fundamental Unit of Type-Level Programming
-
Understanding
typeof Operator at Type Level
-
Understanding
keyof Operator in TypeScript
- What Is Vacuous Truth?
- Indexed Access Types in TypeScript
- Index Signatures in TypeScript
- Mapped Types in TypeScript
- Key Remapping in Mapped Types
- Property Modifiers in Mapped Types
- Conditional Types in TypeScript
- Possible Outcomes of Conditional Types
- Distributive Conditional Types
- Nested Conditionals and Key Removal in Mapped Types
-
The
infer Keyword in Conditional Types
-
Tuple Pattern Matching with
infer Keyword
- Type-Level Recursion with Conditional Types
- Type-Level Arithmetic Operations
- Branded Types in TypeScript
- Real-World Use Cases of Type-Level Programming
Section 9: Utility Types in TypeScript
- Introduction to Utility Types
-
Union Utility Types:
Exclude,
Extract, and
NonNullable -
Property Modifier Utility Types:
Partial,
Required, and
Readonly -
Property Selection Utility Types:
Pick
and
Omit -
Object Mapping Utility Types:
Record -
Function Utility Types:
Parameters
and
ReturnType -
String Manipulation Utility Types:
Uppercase,
Lowercase,
Capitalize, and
Uncapitalize -
Promise Utility Types:
Awaited -
Inference Control Utility Types:
NoInfer - Combining Multiple Utility Types
- Creating Custom Utility Types
- Exploring Third-Party Utility Libraries
- Assignment: TypeScript Type-Challenges
- Additional Resources for Practice
Section 10: Type Narrowing & Control Flow Analysis
- Introduction to Control Flow Analysis
- Type Widening and Type Narrowing in TypeScript
- Type Narrowing Techniques and Purpose
-
Narrowing with
typeof Type Guard
-
Narrowing with
instanceof Type Guard
-
Narrowing with the
in Operator Type Guard
- Equality Narrowing in TypeScript
- Truthiness Narrowing in TypeScript
- Assignment-Based Narrowing in TypeScript
- Discriminated Union Narrowing in TypeScript
- What is a Predicate in Logic and Mathematics?
- User-Defined Type Guards with Type Predicates
-
Assertion Functions and Type Narrowing with
asserts Keyword
- Exhaustiveness Checking in TypeScript
- Type Narrowing in Generic Functions
- Narrowing Across Function Boundaries
- Control Flow Analysis of Aliased Conditions and Discriminants
-
The
satisfies Operator in TypeScript
Section 11: Understanding Modules in TypeScript
- Why Do We Need Modules?
- ES Modules vs CommonJS: The Real Difference
- Importing and Exporting Values
- Mastering Import and Export Patterns
- When to Use Default vs Named Exports
- Re-Exporting Modules Efficiently
- Understanding Type-Only Imports and Exports
- How Module Resolution Works in TypeScript
- Understanding File Extensions in TypeScript Imports
-
Configuring Modules with
module
Compiler Option
-
Configuring Module Resolution with
moduleResolution
Compiler Option
- Understanding Package Entry Points
- Working with Package Exports and Imports
-
Import Attributes and the
with Keyword
- Importing JavaScript Files into TypeScript
- How Node.js Resolves Modules
- Understanding Bare, Relative, and Absolute Imports
- Debugging Module Resolution Problems
Section 12: Ambient Declarations and Declaration Files
- What Are Ambient Declarations?
-
Understanding the
declare Keyword
- Declaring Global Variables
- Declaring Global Functions and Objects
- Global vs Module Scope in TypeScript
-
Declaring Modules Using
declare module - Understanding Ambient Modules
- Wildcard Module Declarations
-
What Are Declaration Files (
.d.ts)?
- Why TypeScript Needs Declaration Files
- Understanding How TypeScript Finds Types
-
Exploring Built-in Declaration Files Like
lib.es6.d.ts - Writing Declaration Files for JavaScript Libraries
-
Understanding
@types and DefinitelyTyped
- Module Augmentation Explained
- Global Augmentation Explained
- Extending Existing Types Safely
- Common Mistakes in Declaration Files
- Mental Model of Ambient Declarations and Declaration Files
-
@ Directives in TypeScript
Section 13: Runtime Type Safety with Zod
- Why Runtime Validation Matters
- Compile-Time vs Runtime Type Safety
-
Why
JSON.parse() is Not Type-Safe?
- Why API Responses are Not Type-Safe?
- Introduction to Zod
- Creating Your First Schema
-
Validating Data with
parse - Object Schemas
- Array Schemas
- Nested Schemas
- Optional and Nullable Fields
- Default Values in Schemas
- Union Schemas
- Literal Schemas
- Validating Strings with Regular Expressions
-
Custom Validation with
refine - Transforming Data During Validation
- Understanding Validation Errors
- Inferring Types from Schemas
- Schema Composition and Reusability
- Type-Safe Data Fetching with Zod
- Building a Reusable API Client with Zod
- Validating API Request Data
- Using Zod with Forms
- Overview of Valibot, ArkType, and Other Alternatives
Section 14: Building a Type-Safe Schema Validation Library
- Designing a Schema Validation Library
- Creating Our First String Validator
- Creating Number and Boolean Validators
- Building a Common Validator Interface
-
Implementing Data Validation with
parse - Building Object Validators
- Building Array Validators
- Implementing Optional Fields
- Adding Custom Validation Rules
- Implementing Method Chaining
- Inferring Static Types from Validators
-
Creating an
Infer Utility Type
- Improving Error Messages
- Supporting Nested Validators
- Building a Complete User Schema
- Testing Our Library
- Limitations of Our Implementation
- How Production Libraries Work Internally
Section 15: TypeScript and the DOM
- Understanding DOM Types in TypeScript
-
Exploring
lib.dom.d.ts and Built-in Browser Types
-
Using
document and window Safely
-
Querying Elements with
querySelector and querySelectorAll -
Handling
null from DOM Queries
-
Type Narrowing for DOM Elements using
instanceof -
Using Type Assertions (
as) with DOM Elements
-
Using Generics with DOM APIs like
querySelector<T> -
Working with Specific Element Types like
HTMLInputElement and HTMLButtonElement -
Understanding
Event and EventTarget -
Typing Event Handlers like
MouseEvent and KeyboardEvent -
Safely Accessing
event.target with Type Guards
- Working with Forms and Inputs in TypeScript
-
Handling DOM Collections like
NodeList and HTMLCollection -
Understanding Differences Between
NodeList and Arrays
- Manipulating DOM Elements with Full Type Safety
Section 16: TypeScript in React
-
Why React Needs TypeScript: Understanding Type Safety in UI
Development
-
Understanding
JSX, TSX, and React's Built-in Type Definitions
-
Typing Function Components: Props, Return Types, and When to Avoid
React.FC -
Typing Props with
type, interface, Optional Props, Default Values, and Readonly Props
-
Typing
children Correctly: ReactNode, ReactElement, JSX.Element, and Function-as-Children
-
Passing Functions as Props: Typing Callbacks, Event Handlers, and
Custom Function Props
-
Typing React Events:
ChangeEvent, MouseEvent, FormEvent, KeyboardEvent, and SyntheticEvent -
Typing
useState: Inference, Explicit Generics, Objects, Arrays, Union Types, and
Nullable State
-
Modeling UI States with TypeScript: Loading, Success, Error, Empty,
and Disabled States
-
Typing
useReducer: State Types, Action Types, Discriminated Unions, and
Exhaustiveness Checking
-
Typing
useRef: DOM Refs, Mutable Refs, Null Handling, and Common Ref Mistakes
-
Typing
forwardRef and useImperativeHandle -
Typing
useEffect, Cleanup Functions, Async Logic, and Dependency Arrays
-
Typing
useMemo and useCallback: Inference, Function Types, and Performance-Related Patterns
-
Typing Custom Hooks: Parameters, Return Types, Tuples, Objects,
Generics, and Reusable Hook APIs
-
Typing React Context API: Creating Safe Contexts, Provider Props,
Custom Context Hooks, and Context with Reducers
-
Typing Forms in React: Controlled Inputs, Form Events, Field Values,
Errors, and Validation Results
-
Runtime Validation in React: Connecting API Data with TypeScript
Using
Zod and z.infer -
Typing CSS in React:
CSSProperties, CSS Modules, Class Names, and Variant-Based Styling
-
Reusing Native HTML Props:
ComponentProps, ComponentPropsWithoutRef, and ComponentPropsWithRef -
Creating Reusable Components with Generics: Lists, Tables, Select
Components, and Data-Driven UI
-
Advanced Component Patterns: Render Props, Compound Components,
Polymorphic Components, and the
as Prop
-
Type-Safe Routing in React: Route Params, Search Params, Navigation
State, and Route Config Objects
-
Common TypeScript Mistakes in React and How to Refactor Unsafe
Components
Section 17: TypeScript in Node.js
-
Why Backend Code Needs TypeScript: Type Safety at Runtime Boundaries
-
Understanding Node.js Type Definitions:
@types/node, Built-in Modules, and Runtime APIs
-
Typing Environment Variables and Configuration:
process.env, Runtime Validation, and Safe Config Objects
-
Typing Async Backend Code:
Promise, async Functions, Error Cases, and unknown Data
-
Understanding Express Types:
Request, Response, NextFunction, and RequestHandler -
Typing Express Requests:
req.params, req.query, req.body, Headers, Cookies, and Files
-
Typing Express Responses:
res.json, Status Codes, Success Responses, Error Responses, and Response
Helpers
-
Typing Route Handlers, Controllers, Services, and Repository Layers
-
Typing Express Middleware: Normal Middleware, Error Middleware, Auth
Middleware, and Reusable Middleware
-
Extending Express Request Safely: Declaration Merging, Auth User,
Role, and Session Data
-
Type-Safe Authentication and Authorization: JWT Payloads, Sessions,
Roles, Permissions, and Protected Routes
-
Runtime Validation in Node.js: Validating Body, Params, Query,
Headers, Cookies, and Environment Variables
-
Using
Zod with Node.js: Schemas, z.infer, Validation Middleware, and Error Formatting
-
Designing Type-Safe API Contracts: Request Types, Response Types,
DTOs, and Shared Types
-
Typing Database Code with Mongoose: Schemas, Models, Documents,
Methods, Statics, and Object IDs
-
Typing Database Code with Prisma: Generated Types, Create Inputs,
Update Inputs, Select, Include, and Query Results
-
Separating Database Types, Domain Types, and API Response Types
Safely
-
Type-Safe Error Handling: Custom Error Classes, Error Codes, Error
Responses, and Result Types
-
Typing External API Calls and Webhooks: Unknown Responses, Runtime
Validation, Event Payloads, and Discriminated Unions
- Typing File Uploads, Buffers, Streams, and Storage Operations
- Typing Background Jobs, Queues, Cron Jobs, and Event Emitters
-
Using Advanced TypeScript Patterns in Backend Code: Branded Types,
Utility Types, Literal Types, and
as const -
End-to-End Type Safety: Sharing Types Between Frontend and Backend
-
Introduction to
tRPC and When It Is Better Than Traditional REST Type Sharing
-
Common TypeScript Mistakes in Node.js and Refactoring Unsafe Backend
Code
Section 18: Production-Grade TypeScript Setup
- Why Most TypeScript Projects Are Misconfigured
- Understanding Modern TypeScript Development Workflows
-
Running TypeScript with
tsc -
Running TypeScript with
ts-node -
Running TypeScript with
tsx - Native TypeScript Support in Node.js
- Development vs Production Workflows
-
Creating a Reusable Base
tsconfig.json -
Understanding
strict Mode
-
Making Indexed Access Safer with
noUncheckedIndexedAccess -
Understanding
exactOptionalPropertyTypes -
Understanding
noImplicitOverride - Useful Compiler Options for Real-World Projects
- Understanding Path Aliases in TypeScript
-
Configuring Path Aliases with
baseUrl and paths - Using Path Aliases in Frontend Applications
- Using Path Aliases in Node.js Applications
- Runtime Challenges of Path Aliases
- When Not to Use Path Aliases
- Alternatives to Path Aliases
- Setting Up ESLint with TypeScript
- Setting Up Prettier
- Recommended VS Code Settings for TypeScript
- Type Checking in CI/CD Pipelines
- Building a Production-Ready TypeScript Project
Section 19: Understanding TypeScript Runtime Features
- Why Some TypeScript Features Generate Runtime Code
-
Understanding the
erasableSyntaxOnly Option
- Compile-Time vs Runtime in TypeScript
- What Gets Erased and What Stays After Compilation
- Understanding TypeScript Code Generation
- Introduction to Enums in TypeScript
- Numeric Enums and Their Runtime Behavior
- String Enums and Differences from Numeric Enums
- Reverse Mapping in Enums Explained
- Const Enums and Compile-Time Optimization
- Enums vs Union Types (When to Use What)
- Enums vs Objects as Alternatives
- Why TypeScript Introduced Namespaces
- Understanding Namespaces in TypeScript
- Namespace Augmentation
- Namespaces vs ES Modules
- Namespaces and Their Runtime Impact
- Node.js Native TypeScript Support Explained
- Mental Model of TypeScript Runtime Features
Section 20: Object Oriented Programming in TypeScript
- How Interfaces Bring Structure to Your Code
- Interface Inheritance and Reuse Done Right
- Interface vs Type Alias: When to Use Which
- Creating and Initializing Classes Like a Pro
- Demystifying Public, Private, and Protected Modifiers
- The Power of Readonly and Optional Properties
- Inheritance Explained with Real World Examples
- When to Use Abstract Classes and When Not To
- Implementing Interfaces in Your Classes
- Why Composition Often Beats Inheritance
- Parameter Properties in Classes in Runtime
Section 21: Understanding Decorators in TypeScript
- What Decorators Really Are and Why They Exist
- Understanding the Decorator Execution Model
- Creating Class Decorators
- Creating Method Decorators
- Creating Property Decorators
- Creating Accessor Decorators
- Creating Parameter Decorators
- Building Reusable Decorator Factories
- Reflect Metadata API Explained
- Creating Custom Metadata with Reflect Metadata
- Building Validation Using Decorators and Metadata
- How Angular, NestJS, and TypeORM Use Decorators
- Legacy Decorators vs Standard ECMAScript Decorators
- What Is Changing in the New Decorator Proposal
- Mental Model of Decorators in TypeScript
Section 22: Using JSDoc with TypeScript
- What JSDoc Is and Why It Still Matters
- Adding Type Hints in JavaScript Files with JSDoc
-
Setting Up
checkJs
and
allowJs
in tsconfig
-
Using
@param,
@returns, and
@typedef
Tags Correctly
-
Creating Custom Types and Objects with
@typedef
and
@callback - Working with Generics in JSDoc Comments
- Mixing JSDoc and TypeScript Files in One Project
- Generating Documentation Automatically from JSDoc
- Migrating from JSDoc to Real TypeScript Files Step by Step
Section 23: Advanced TypeScript Concepts
- Why TypeScript Is Not a Sound Type System
- Understanding Soundness and Unsoundness
- What Is Covariance?
- What Is Contravariance?
- What Is Invariance?
- Variance in Function Parameters
- Variance in Arrays and Collections
- Mental Model of Variance in TypeScript
Section 24: Hacking the TypeScript Compiler 🗿
- Exploring the TypeScript Codebase
- Cloning and Building TypeScript from Source
- Running a Custom TypeScript Compiler Locally
- Understanding the TypeScript Compiler
- Tracing a TypeScript Error Through the Source Code
- Adding Our Own Compiler Diagnostics
- Creating a Custom Compiler Error Message
- Implementing a New TypeScript Compiler Feature
- Adding a Custom Intrinsic Utility Type
- Creating Our Own Type-Level Keywords
- Modifying Type Inference Behavior
- Understanding How Built-in Utility Types Work
- How TypeScript Powers VS Code
- Exploring the TypeScript Language Server
- Building and Using Our Custom TypeScript Version
- Mental Model of the TypeScript Compiler