# TypeScript Exercises

## Exercise 1: Typed API Response

**Task:** Define an interface `ApiResponse<T>` with `data: T`, `status: number`, and `message?: string`. Create a `User` interface and type a variable as `ApiResponse<User>`.

**Validation:**
- [ ] ApiResponse is generic over the data shape
- [ ] status is required, message is optional
- [ ] Compiler catches missing or wrong-typed fields

**Hints:**
1. `interface ApiResponse<T> { data: T; ... }`
2. Use `?` for optional properties
3. `ApiResponse<User>` means T = User

---

## Exercise 2: Discriminated Union

**Task:** Create a type `Result` that is either `{ kind: 'ok'; value: number }` or `{ kind: 'error'; message: string }`. Write a function `unwrap(r: Result): number` that returns the value or throws the message.

**Validation:**
- [ ] Function uses `r.kind` to narrow
- [ ] In the 'ok' branch, `r.value` is accessible
- [ ] In the 'error' branch, `r.message` is accessible

**Hints:**
1. `type Result = OkResult | ErrorResult` with shared `kind`
2. `if (r.kind === 'ok') return r.value;`
3. Discriminated unions narrow on a common literal field

---

## Exercise 3: Generic Map Function

**Task:** Implement `map<T, U>(arr: T[], fn: (item: T) => U): U[]` — the standard array map. Ensure the types flow correctly from input to output.

**Validation:**
- [ ] `map([1,2,3], x => x * 2)` returns `number[]`
- [ ] `map(["a","b"], s => s.length)` returns `number[]`
- [ ] Wrong callback signature is rejected

**Hints:**
1. Two type parameters: T for input, U for output
2. `fn` takes `T` and returns `U`
3. Return type is `U[]`

---

## Exercise 4: Strict Null Safety

**Task:** Enable strict null checks (if not already). Write a function `getLength(s: string | null): number` that returns 0 for null and the length otherwise. Don't use non-null assertion (`!`).

**Validation:**
- [ ] `getLength(null)` returns 0
- [ ] `getLength("hi")` returns 2
- [ ] No `!` used; narrowing handles null

**Hints:**
1. `if (s === null) return 0;`
2. After the check, `s` is narrowed to string
3. Or use ternary: `s ? s.length : 0`

---

## Exercise 5: Pick and Omit

**Task:** Given `interface Config { apiUrl: string; timeout: number; secret: string }`, create a type `PublicConfig` that excludes `secret` using `Omit`. Create `TimeoutOnly` using `Pick` with just `timeout`.

**Validation:**
- [ ] PublicConfig has apiUrl and timeout, not secret
- [ ] TimeoutOnly has only timeout
- [ ] Uses built-in utility types

**Hints:**
1. `Omit<Config, 'secret'>`
2. `Pick<Config, 'timeout'>`
3. Can combine: `Pick<Omit<Config, 'secret'>, 'apiUrl'>`
