# TypeScript Walkthrough — Learn by Doing

## Step 1: Your First Types

Let's add types to a simple function.

<!-- hint:code language="typescript" highlight="1,3" -->

**Embed:** https://www.typescriptlang.org/play

**Task:** Write a function `add(a, b)` that adds two numbers. Add explicit parameter and return types. Call it with numbers and observe the output.

**Question:** What happens if you try to call `add("1", "2")`? What does the compiler tell you, and what would JavaScript do at runtime?

**Checkpoint:** The user understands that TypeScript rejects invalid argument types at compile time.

---

## Step 2: Interfaces

<!-- hint:code language="typescript" highlight="1,4" -->

**Task:** Define an interface `Product` with `id`, `name`, and `price`. Create a function `formatProduct(p: Product)` that returns a string like "Product: name ($price)".

**Question:** What happens if you pass an object that has extra properties? What about one missing `price`?

**Checkpoint:** The user can define and use interfaces, and understands excess property checks and required vs optional fields.

---

## Step 3: Unions and Narrowing

**Task:** Write a function `double(x: string | number)` that returns the string repeated twice if it's a string, or the number multiplied by 2 if it's a number. Use `typeof` to narrow.

**Question:** Why do we need the `typeof` check? What would TypeScript infer about `x` without it?

**Checkpoint:** The user can narrow union types and explain why it's necessary.

---

## Step 4: Generics

<!-- hint:card type="concept" title="Generics let TypeScript infer types from usage — T is resolved when you call the function" -->

**Task:** Write a generic function `first<T>(arr: T[]): T | undefined` that returns the first element of an array. Test it with number and string arrays.

**Question:** How does TypeScript know the return type when you call `first([1, 2, 3])`? Where does `T` get its value?

**Checkpoint:** The user understands generic type inference from usage.

---

## Step 5: Generic Constraints

**Task:** Write `getProperty<T, K extends keyof T>(obj: T, key: K): T[K]` that safely gets a property. The compiler should ensure `key` is a valid key of `obj`.

**Question:** What does `K extends keyof T` mean? Why can't we just use `string` for the key?

**Checkpoint:** The user can use `keyof` and constrained generics.

---

## Step 6: Utility Types

<!-- hint:celebrate -->

**Task:** Given a `User` interface, create a type `UserUpdate` where all fields are optional (using `Partial`). Create a function that accepts `UserUpdate` and merges it into an existing user.

**Question:** When would you use `Partial` vs defining a separate interface with optional fields?

**Checkpoint:** The user can apply utility types for common patterns.
