> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript Crash Course

> Master the typed superset of JavaScript that scales

# TypeScript Crash Course

> **TypeScript** is JavaScript with superpowers. It adds static typing to JavaScript, catching errors at compile time instead of runtime. If you're building anything serious -- from React apps to Node.js APIs -- TypeScript is the industry standard.

Think of TypeScript as a contract system for your code. In plain JavaScript, passing an object to a function is like handing someone an unmarked envelope -- they have no idea what is inside until they open it (at runtime). TypeScript puts a label on every envelope: "This contains a User with id, name, and email." If you try to pass the wrong envelope, the compiler catches it before anyone opens it.

This crash course takes you from basic types to advanced patterns like generics, decorators, and type gymnastics.

***

## Why TypeScript?

TypeScript has become the default choice for professional JavaScript development.

<CardGroup cols={2}>
  <Card title="Catch Errors Early" icon="bug-slash">
    Static typing catches bugs before your code runs. No more "undefined is not a function" in production.
  </Card>

  <Card title="Better IDE Experience" icon="wand-magic-sparkles">
    Autocomplete, refactoring, and inline documentation powered by the type system.
  </Card>

  <Card title="Scales with Your Team" icon="users">
    Types serve as documentation. Large codebases become manageable and self-documenting.
  </Card>

  <Card title="JavaScript Compatible" icon="arrows-rotate">
    TypeScript is a superset of JavaScript. Any valid JS is valid TS. Migrate gradually.
  </Card>
</CardGroup>

## Course Roadmap

We'll build your TypeScript knowledge from the ground up.

<Steps>
  <Step title="Fundamentals">
    Types, type inference, and basic annotations.
    [Start Learning](/courses/typescript-crash-course/fundamentals)
  </Step>

  <Step title="Functions & Types">
    Function types, overloads, generics basics, and type guards.
    [Master Functions](/courses/typescript-crash-course/functions-types)
  </Step>

  <Step title="Objects & Interfaces">
    Interfaces, type aliases, optional properties, and index signatures.
    [Define Structures](/courses/typescript-crash-course/objects-interfaces)
  </Step>

  <Step title="Classes & OOP">
    Classes, access modifiers, abstract classes, and decorators.
    [Go Object-Oriented](/courses/typescript-crash-course/classes-oop)
  </Step>

  <Step title="Advanced Types">
    Union, intersection, conditional types, mapped types, and utility types.
    [Level Up](/courses/typescript-crash-course/advanced-types)
  </Step>

  <Step title="Generics Deep Dive">
    Generic functions, classes, constraints, and real-world patterns.
    [Master Generics](/courses/typescript-crash-course/generics)
  </Step>

  <Step title="Modules & Configuration">
    ES modules, namespaces, tsconfig.json, and project setup.
    [Configure Projects](/courses/typescript-crash-course/modules-config)
  </Step>
</Steps>

## Prerequisites

* Strong understanding of JavaScript (ES6+).
* Familiarity with Node.js and npm.
* Basic understanding of object-oriented concepts.
* A code editor with TypeScript support (VS Code recommended).

## The TypeScript Philosophy

> "TypeScript is a strict syntactical superset of JavaScript that adds optional static typing." — Microsoft

TypeScript's design goals:

* **Statically identify constructs that are likely to be errors.**
* **Provide a structuring mechanism for larger pieces of code.**
* **Impose no runtime overhead on emitted programs.**
* **Align with current and future ECMAScript proposals.**

```typescript theme={null}
// A taste of TypeScript

// An interface is a contract: any object claiming to be a "User"
// MUST have exactly these properties with these types.
interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user' | 'guest'; // Union type: only these 3 strings are allowed
}

// Parameter types and return types are explicit -- no guessing what this function expects
function greetUser(user: User): string {
  return `Hello, ${user.name}! You are logged in as ${user.role}.`;
}

// TypeScript checks this object against the User interface at compile time.
// Missing a property? Wrong type? You will know before the code ever runs.
const user: User = {
  id: 1,
  name: 'Alice',
  email: 'alice@example.com',
  role: 'admin'
};

console.log(greetUser(user)); // "Hello, Alice! You are logged in as admin."
```

***

## Setting Up TypeScript

### Installation

```bash theme={null}
# Install globally
npm install -g typescript

# Check version
tsc --version

# Initialize a project
tsc --init
```

### Your First TypeScript File

```typescript theme={null}
// hello.ts
function greet(name: string): string {
  return `Hello, ${name}!`;
}

console.log(greet('World'));
```

```bash theme={null}
# Compile to JavaScript
tsc hello.ts

# Run the compiled JS
node hello.js
```

### Using ts-node (No Compile Step)

```bash theme={null}
# Install ts-node
npm install -g ts-node

# Run TypeScript directly
ts-node hello.ts
```

<Tip>
  **Pro Tip**: Use `tsx` for even faster execution: `npm install -g tsx && tsx hello.ts`
</Tip>

***

## TypeScript vs JavaScript

| Feature         | JavaScript   | TypeScript                       |
| :-------------- | :----------- | :------------------------------- |
| Type System     | Dynamic      | Static (optional)                |
| Error Detection | Runtime      | Compile time                     |
| IDE Support     | Basic        | Rich (autocomplete, refactoring) |
| Learning Curve  | Lower        | Higher (but worth it)            |
| Compilation     | Not required | Required (to JS)                 |
| Adoption        | Universal    | Growing rapidly                  |

***

Let's dive into the fundamentals and start writing type-safe code!

***

## Interview Deep-Dive

<AccordionGroup>
  <Accordion title="Q: A teammate argues that TypeScript is just 'extra work for no real benefit' since the types disappear at runtime. How do you respond?">
    **Strong Answer:**

    This is a surprisingly common objection, and it reveals a misunderstanding of where TypeScript's value lies. The types disappearing at runtime is a feature, not a weakness.

    * **Types are a development-time safety net**: TypeScript catches an entire category of bugs before the code ever executes -- null reference errors, misspelled property names, wrong argument types, missing function parameters. In a 2019 study by Airbnb, 38% of bugs that made it to production could have been prevented by TypeScript. That is not "extra work" -- that is preventing on-call pages.
    * **Zero runtime cost**: Because types are erased during compilation, TypeScript adds exactly zero bytes to your production bundle and zero milliseconds to your execution time. Compare this to runtime validation libraries (Joi, Zod) that add bundle size and CPU overhead. TypeScript gives you the safety for free at build time.
    * **IDE experience is the real killer feature**: Autocomplete, inline documentation, safe refactoring (rename a property and every usage updates), and jump-to-definition across the codebase. These are not nice-to-haves -- they fundamentally change how fast a developer can navigate and modify a large codebase. A team of 10 engineers working on 200K lines of untyped JavaScript spends a meaningful percentage of their time reading code to understand data shapes. TypeScript makes the shapes self-documenting.
    * **The "extra work" argument only holds for toy projects**: For a 50-line script, TypeScript is overhead. For a 50,000-line application with 10 contributors, it is the difference between "I can confidently refactor this module" and "I am afraid to touch this code because I do not know what will break."

    The trade-off is real but asymmetric: you invest time upfront writing types, and you save multiples of that time downstream in debugging, onboarding, and refactoring.

    **Follow-up: When would you genuinely recommend NOT using TypeScript?**

    Quick prototypes or throwaway scripts where the code will live less than a week and be written by one person. One-off data migration scripts. Small Lambda functions under 100 lines where the input/output shapes are trivial. The decision threshold is roughly: if the code will be maintained by someone other than the original author, or will live longer than a sprint, TypeScript pays for itself.
  </Accordion>

  <Accordion title="Q: Explain TypeScript's structural type system versus a nominal type system like Java's. Why does this distinction matter for how you design TypeScript code?">
    **Strong Answer:**

    This is one of the most fundamental concepts in TypeScript and the source of many "it compiles but it should not" surprises for developers coming from Java or C#.

    * **Structural typing (TypeScript)**: Two types are compatible if their shapes match -- if they have the same properties with the same types, they are interchangeable regardless of their names. If I define `interface Dog { name: string }` and `interface Cat { name: string }`, a `Cat` can be assigned to a `Dog` variable because they have the same structure. TypeScript does not care what you called the type; it cares what the type contains.
    * **Nominal typing (Java)**: Two types are compatible only if they are explicitly declared as related (via `extends` or `implements`). Even if `Dog` and `Cat` have identical fields, they are different types because they have different names.
    * **Why it matters for design**: In TypeScript, you cannot rely on type names for safety. If you have `type UserId = string` and `type OrderId = string`, TypeScript treats them as interchangeable -- you can pass an `OrderId` where a `UserId` is expected. In Java, these would be distinct types that the compiler enforces. To get nominal-like behavior in TypeScript, you need the "branded types" pattern: `type UserId = string & { readonly __brand: 'UserId' }`.
    * **The upside of structural typing**: It makes TypeScript incredibly flexible for working with JavaScript's duck-typed ecosystem. You can define an interface for a library's callback shape without importing the library's types. If the callback matches your interface, TypeScript accepts it. This is why TypeScript integrates so smoothly with existing JavaScript -- it does not require every library to formally declare type relationships.

    **Follow-up: Show me how you would implement branded types to prevent mixing up UserId and OrderId.**

    The pattern uses intersection with a phantom property that exists only at the type level: `type UserId = string & { readonly __brand: unique symbol }`. You create factory functions: `function createUserId(id: string): UserId { return id as UserId }`. Now `createUserId('123')` returns a `UserId`, and passing it to a function expecting `OrderId` produces a compile error. The `__brand` property does not exist at runtime -- it is purely a type-level trick. This is the standard approach in production TypeScript codebases where domain safety matters (financial systems, multi-tenant platforms).
  </Accordion>

  <Accordion title="Q: Walk me through what happens when you run 'tsc' on a TypeScript file. What are the stages of the compilation pipeline?">
    **Strong Answer:**

    The TypeScript compiler has four distinct stages, and understanding them explains why certain errors appear when they do.

    * **Stage 1 -- Lexing**: The source code is broken into tokens (keywords, identifiers, operators, literals). `let x: number = 5` becomes tokens: `let`, `x`, `:`, `number`, `=`, `5`. This is a mechanical process that fails only on truly malformed input (unclosed strings, invalid characters).
    * **Stage 2 -- Parsing**: Tokens are assembled into an Abstract Syntax Tree (AST). The parser understands JavaScript and TypeScript grammar -- it knows that `let x: number = 5` is a variable declaration with a type annotation. Syntax errors are caught here: missing semicolons, unmatched brackets, invalid expression structure.
    * **Stage 3 -- Type Checking**: This is where TypeScript earns its keep. The type checker walks the AST and validates that every operation is type-safe. It resolves type references, checks assignment compatibility, infers types where annotations are missing, and reports the "red squiggle" errors you see in your IDE. This stage uses TypeScript's structural type system, control flow analysis, and all the advanced type features (conditional types, mapped types, generics). This is by far the most computationally expensive stage.
    * **Stage 4 -- Emitting**: The typed AST is transformed into JavaScript. All type annotations, interfaces, type aliases, and enums (for `const enum`) are stripped. The output is plain JavaScript that any runtime can execute. The emitter also generates `.d.ts` declaration files and source maps if configured.

    The critical insight is type erasure: after Stage 4, there is no TypeScript. The runtime never sees types. This means you cannot use TypeScript types for runtime decisions -- `if (x instanceof MyType)` does not work for interfaces because interfaces do not exist at runtime. You need runtime type guards (`typeof`, `instanceof` for classes, or custom validation functions).

    **Follow-up: If type checking is the expensive stage, how do large projects manage compilation performance?**

    Three strategies. First, `--incremental` mode: TypeScript caches the AST and type information from the previous compilation and only re-checks files that changed. This can reduce rebuild times from 30 seconds to under 2 seconds for a large project. Second, Project References with `--build` mode: split a monorepo into smaller sub-projects that are compiled independently. A change in `packages/ui` does not re-check `packages/server`. Third, tools like `esbuild` or `swc` that skip type checking entirely and only do Stage 1, 2, and 4 (lexing, parsing, emitting). They rely on `tsc --noEmit` running separately (often in CI) to catch type errors. This gives you sub-second build times during development while still catching type errors before merge.
  </Accordion>
</AccordionGroup>
