Skip to content

Complete TypeScript Programming Study Guide

flowchart TD
    A[Hub] --> B[Key Concepts]
    A --> C[Core Principles]
    A --> D[Practical Applications]
    B --> E[Fundamental definitions]
    C --> F[Design patterns]
    D --> G[Real-world usage]

TypeScript adds a static type system to JavaScript. It catches bugs at compile time, enables better tooling, and makes large codebases maintainable. TypeScript’s type system is structural — types are compatible based on their shape, not their name. This makes TypeScript flexible while still providing safety. TypeScript is the dominant language for frontend development with React, Angular, and Vue, and is increasingly used for backend development with Node.js and Deno.

This hub page maps every resource on this site. The learning path takes you from TypeScript’s core type system through generics, utility types, and React patterns, building a thorough understanding of how to write type-safe, maintainable JavaScript code.


TypeScript’s type system is the foundation of everything else. Understanding primitive types, literal types, union types, and type narrowing is essential for writing type-safe code.

Literal types — TypeScript can narrow a type to a specific value. A string literal type like Direction defined as a union of "up" | "down" | "left" | "right" enables precise type constraints and catches invalid values at compile time.

Discriminated unions — A union of types that share a common discriminant field. A Result type with a status discriminant allows TypeScript to narrow the type based on the discriminant value, enabling exhaustive pattern matching.

Type narrowing — The compiler narrows types based on control flow. typeof x === "string" narrows x to string inside the if block. The in operator narrows objects to include specific properties. Discriminated unions narrow based on tag values.


Interfaces and type aliases define the shape of objects. Interfaces are extensible and support declaration merging. Type aliases are more flexible and can represent unions, intersections, and mapped types.

Interfaces vs type aliases — Interfaces support declaration merging (you can add properties across multiple declarations) and are easier to extend. Type aliases can represent unions, intersections, and more complex types. Use interfaces for object shapes and type aliases for unions and computed types.

Optional and readonlyname?: string makes a property optional. readonly id: number makes a property immutable. Optional properties are common in configuration objects and API responses.

Index signatures{ [key: string]: number } defines an object with string keys and number values. Record<string, number> is the utility type equivalent. Index signatures are useful for dictionaries and dynamic data.


Generics enable you to write code that works with any type while preserving type information. They are the foundation of reusable, type-safe libraries and data structures.

Type parametersfunction identity<T>(arg: T): T { return arg } works for any type. The compiler infers the type from the argument. You can also specify the type explicitly: identity<string>("hello").

Generic constraintsfunction getProperty<T, K extends keyof T>(obj: T, key: K): T[K] constrains K to be a key of T. This provides type-safe property access while maintaining generality.

Utility type generics — Most utility types are generic: Partial<T>, Required<T>, Pick<T, K>, Omit<T, K>. Understanding how generics work is essential for using these types effectively.


TypeScript provides built-in utility types that transform and manipulate types. These types are essential for working with APIs, databases, and complex data structures.

Partial and RequiredPartial<T> makes all properties optional. Required<T> makes all properties required. These are essential for update operations where you only provide some fields.

Pick and OmitPick<T, "name" | "age"> extracts specific properties. Omit<T, "password"> removes specific properties. These are essential for API request/response types.

Conditional typesT extends U ? X : Y evaluates to X if T extends U, otherwise Y. Combined with infer, conditional types enable powerful type transformations: extracting return types, unwrapping promise types, and flattening union types.


These patterns enable sophisticated type-level programming. They are essential for writing type-safe libraries and complex applications.

Mapped types{ [K in keyof T]: NewType } iterates over the keys of T and transforms each property. This is how Partial, Required, and Readonly are implemented. Mapped types enable type-level iteration.

Template literal types — TypeScript can manipulate strings at the type level. type EventName ={"click" | "hover"}_{“start” | “end”}“ produces a union of four string literal types. Template literal types enable type-safe event systems and API routes.

Branded types — TypeScript’s structural type system treats all objects with the same shape as compatible. Branded types add a phantom property to distinguish types: type UserId = string & { readonly __brand: unique symbol }. This prevents mixing UserId with other strings.


TypeScript and React are a powerful combination. TypeScript provides type safety for props, state, hooks, and event handlers. React’s component model pairs naturally with TypeScript’s interface system.

Typing props — Define an interface for component props: interface ButtonProps { label: string; onClick: () => void; variant?: "primary" | "secondary" }. Optional props use ?. Destructure props in the component signature for clarity.

Typing hooksuseState<string>("") types the state. useState<number | null>(null) types a nullable state. useRef<HTMLInputElement>(null) types the ref. Custom hooks return typed values.

Event handlersReact.ChangeEvent<HTMLInputElement> types input change events. React.MouseEvent<HTMLButtonElement> types button clicks. React.FormEvent<HTMLFormElement> types form submissions.


TypeScript builds on JavaScript knowledge. Follow this progression to build type-safe code.

  • Learn primitive types, literal types, and unions
  • Understand interfaces and type aliases
  • Study type narrowing and control flow analysis

Stage 2: Generics and Utility Types (Weeks 4–6)

Section titled “Stage 2: Generics and Utility Types (Weeks 4–6)”
  • Master generics and generic constraints
  • Learn the built-in utility types — Partial, Pick, Omit, Record
  • Study conditional types and mapped types

Stage 3: React with TypeScript (Weeks 7–10)

Section titled “Stage 3: React with TypeScript (Weeks 7–10)”
  • Type component props and state
  • Learn typed hooks and event handlers
  • Study context, providers, and advanced patterns

Stage 4: Advanced Patterns (Weeks 11–14)

Section titled “Stage 4: Advanced Patterns (Weeks 11–14)”
  • Study branded types and nominal typing
  • Learn template literal types and string manipulation
  • Build a type-safe library or application

Wyatt’s Notes is a network of interconnected programming and study sites:


Should I learn JavaScript or TypeScript first?

Section titled “Should I learn JavaScript or TypeScript first?”

Learn JavaScript first. TypeScript is a superset of JavaScript — everything you learn in JavaScript applies to TypeScript. Understanding JavaScript’s quirks, runtime behavior, and ecosystem makes TypeScript easier to learn and more meaningful.

Is TypeScript just for frontend development?

Section titled “Is TypeScript just for frontend development?”

No. TypeScript is used for frontend (React, Angular, Vue), backend (Node.js, Deno, Bun), full-stack (Next.js, Remix), mobile (React Native), and desktop (Electron) development. TypeScript is a general-purpose language that compiles to JavaScript.

What is the difference between interface and type alias?

Section titled “What is the difference between interface and type alias?”

Interfaces support declaration merging and are easier to extend with extends. Type aliases can represent unions, intersections, and more complex types. Use interfaces for object shapes that may be extended. Use type aliases for unions, intersections, and computed types.

It is strongly recommended. TypeScript catches prop errors at compile time, provides better autocompletion, and makes refactoring safer. The React ecosystem has excellent TypeScript support. Most new React projects use TypeScript.

What are utility types and when should I use them?

Section titled “What are utility types and when should I use them?”

Utility types are built-in types that transform other types. Partial makes properties optional. Pick extracts specific properties. Omit removes properties. Record creates object types. Use them to derive types from existing interfaces instead of duplicating definitions.

Define interfaces for your API responses: interface ApiResponse<T> { data: T; status: number; message: string }. Use generics to make the response type parameterized. Libraries like Zod can validate and type API responses at runtime.


Last updated: 24 July 2026

Written by Wyatt. For questions or feedback, visit wyattau.com.