fix: lesson 4

This commit is contained in:
Tim Rijkse
2026-03-02 14:45:39 +01:00
parent d021fe8379
commit 63f84655e0
13 changed files with 4953 additions and 235 deletions

View File

@@ -0,0 +1,620 @@
# TypeScript Escaperoom 🔐
Welkom in de TypeScript Escaperoom! Je bent opgesloten in 8 kamers vol met type-puzzels. Je enige kans op vrijheid? Het juiste type op de juiste plaats zetten. Ga je het redden?
---
## Wat ga je doen?
Je gaat een interactieve "escaperoom" doorlopen in TypeScript. Er zijn **8 kamers**, elk met TypeScript puzzels die steeds moeilijker worden. Je taak: **fix alle type errors zodat de code compileert zonder fouten**.
Als je alle kamers hebt opgelost, voert je project automatisch uit en ontvang je de **escape code** — het bewijs dat je echt bent ontsnapt!
Dit is geen standaard oefening — dit is **gamification** zoals het hoort te zijn. Je gaat TypeScript types niet zomaar "leren", je gaat ze **meesteren** door ze in actie toe te passen.
### Waarom dit format?
- 🎮 **Gamified**: Elke kamer is een mini-challenge met increasing difficulty
- 🏁 **Doel-gericht**: Je weet EXACT wanneer je klaar bent (de escape code!)
- 💡 **Hands-on**: Je leert door té DOEN, niet door té LEZEN
-**Cursor-friendly**: Perfect voor het gebruik van Cursor's AI-features
---
## Setup (5 minuten)
Volg deze stappen voordat je begint:
### Stap 1: Download het project
- Ga naar de **Teams channel** voor Les 4
- Download het bestand: `les4-typescript-escaperoom.zip`
- Pak het uit in een nieuwe folder
### Stap 2: Open in Cursor
- Open de folder in **Cursor** (of VS Code)
- Zorg dat je het root-level bestand ziet: `package.json`
### Stap 3: Installeer dependencies
```bash
npm install
```
Dit installeert TypeScript en alle tools die je nodig hebt.
### Stap 4: Maak je ready
```bash
npm run check
```
Je ziet nu een overzicht van alle kamers en welke errors nog opgelost moeten worden. Dit commando voer je regelmatig uit om je voortgang te tracken.
### Stap 5: Begin!
Lees de rest van dit document en start bij **Kamer 1**.
---
## De 8 Kamers
Elke kamer bevat een TypeScript-bestand met fouten en taken. De difficulty loopt op van ⭐ (makkelijk) naar ⭐⭐⭐ (moeilijk).
---
### 🚪 Kamer 1: Basic Types
**Moeilijkheid:** ⭐ Makkelijk
**Bestand:** `src/kamer1-basics.ts`
#### Doel
Fix de **type annotations** op variabelen. TypeScript geeft je rode squiggles — jouw taak is die weg te krijgen door juiste types toe te voegen.
#### Wat je gaat leren
- Basis TypeScript types: `string`, `number`, `boolean`
- Arrays typen: `string[]` en `number[]`
- Type annotations schrijven: `let x: string = "hello"`
#### De Challenge
Het bestand bevat variabelen zonder types OF met foute types. Bijvoorbeeld:
```typescript
let name = "Alice"; // ❌ Mis je type hier?
let age: string = 25; // ❌ Verkeerde type!
let hobbies = ["chess"]; // ❌ Welk array-type?
```
Jouw taak: Maak alle types **expliciet en correct**.
#### Hints
- 💡 Hover over rode errors in Cursor — de error message vertelt je precies wat fout is
- 💡 Probeer eerst jezelf — dit is de makkelijkste kamer, je lukt het!
- 💡 `let x: Type = value` is de syntax
---
### 🚪 Kamer 2: Type Inference
**Moeilijkheid:** ⭐ Makkelijk
**Bestand:** `src/kamer2-inference.ts`
#### Doel
Dit is een "**omgekeerde puzzle**". In plaats van types ÁF te schrijven, verwijder je onnodige types. TypeScript kan namelijk veel types **zelf afleiden** (inferren).
#### Wat je gaat leren
- Wanneer TypeScript types automatisch kan inferren
- Dat expliciete types niet altijd nodig zijn
- **Schone code** = minimale redundantie
#### De Challenge
Het bestand zit vol met **overexpliciet getypte** code:
```typescript
let count: number = 42; // ❌ Overbodig, TypeScript ziet het al
const message: string = "Hello"; // ❌ Overbodig
let items: boolean[] = [true, false]; // ❌ Overbodig
```
Maar sommige types MOETEN blijven:
```typescript
function calculate(x: number, y: number): number { } // ✅ Nodig!
```
Jouw taak: Verwijder onnodige type annotations, houd de essentiële.
#### Hints
- 💡 Rule of thumb: functie parameters en return types altijd typen, lokale variabelen zelden
- 💡 `npm run check` zal je zeggen wat je mist
- 💡 Dit is nog steeds makkelijk — je bent warm up!
---
### 🚪 Kamer 3: Interfaces
**Moeilijkheid:** ⭐⭐ Medium
**Bestand:** `src/kamer3-interfaces.ts`
#### Doel
Nu ga je zelf **interfaces schrijven** voor objecten. Interfaces beschrijven de "vorm" van een object — welke properties het moet hebben en welke types die hebben.
#### Wat je gaat leren
- Interfaces definiëren: `interface User { ... }`
- Eigenschappen annotate: `name: string`
- Nested properties en objecten
- Objects aan interfaces binden
#### De Challenge
Je krijgt objecten zonder types. Jij schrijft de interface:
```typescript
// Gegeven:
const user = {
name: "Alice",
age: 30,
email: "alice@example.com"
};
// Jouw taak: Schrijf interface User { ... }
// En maak: const user: User = { ... }
```
Sommige objecten zijn **genest** (objects in objects):
```typescript
const person = {
name: "Bob",
address: {
street: "Main St",
city: "Amsterdam"
}
};
// Dit vereist nested interface definitions!
```
#### Hints
- 💡 Interfaces beginnen met een HOOFDLETTER: `interface User`, niet `interface user`
- 💡 Voor nested objects maak je nested interfaces
- 💡 Syntax: `interface Name { prop: Type; otherProp: Type; }`
---
### 🚪 Kamer 4: Optional Properties
**Moeilijkheid:** ⭐⭐ Medium
**Bestand:** `src/kamer4-optionals.ts`
#### Doel
Niet alle properties zijn altijd aanwezig. Je leert **optionele properties** (`?`) te gebruiken — als iets "misschien" aanwezig is.
#### Wat je gaat leren
- Optionele properties: `property?: Type`
- Het verschil tussen `undefined` en "niet aanwezig"
- Praktische use cases (formulieren, API responses)
#### De Challenge
Je interfaces hebben properties die soms aanwezig zijn, soms niet:
```typescript
interface User {
name: string; // ✅ ALTIJD nodig
nickname: ?; // ❌ SOMS nodig — use ?
phone?: string; // ✅ Dit is correct!
address?: {
street: string;
city: string;
};
}
```
Zeg voor elke property: "is dit ALWAYS nodig, of SOMETIMES?" Met `?` zeg je "sometimes".
#### Hints
- 💡 `property?: Type` = "optioneel"
- 💡 Zorg dat je objects niet meer/minder properties hebben dan je interface zegt
- 💡 Optionele properties kunnen `undefined` zijn
---
### 🚪 Kamer 5: Union Types
**Moeilijkheid:** ⭐⭐ Medium
**Bestand:** `src/kamer5-unions.ts`
#### Doel
Soms kan een variable **meerdere types** hebben. Dat is wat "union types" zijn: `Type1 | Type2`. Je leert ze gebruiken voor flexibele, veilige code.
#### Wat je gaat leren
- Union types: `string | number`
- Literal types: `"success" | "error"`
- Basis type narrowing (checken welk type het werkelijk is)
#### De Challenge
Je krijgt code met dingen die meerdere types kunnen zijn:
```typescript
// Een ID kan string OF number zijn
let userId: ?; // = string | number
// Een status is altijd één van deze waarden
let status: ?; // = "pending" | "complete" | "failed"
// Een waarde kan string, number, OF boolean zijn
function format(value: ?): string {
// Jouw taak: zeg wat de mogelijke types zijn
}
```
Je moet ook **type narrowing** gebruiken — checken wat het type werkelijk is:
```typescript
if (typeof userId === "string") {
// In dit blok WEET TypeScript dat userId een string is
}
```
#### Hints
- 💡 Syntax: `Type1 | Type2 | Type3` (met pipes)
- 💡 Literal types zijn strings/numbers in quotes: `"success"`, not `success`
- 💡 Use `typeof` checks om te zien wat je hebt
---
### 🚪 Kamer 6: Type Aliases
**Moeilijkheid:** ⭐⭐ Medium
**Bestand:** `src/kamer6-aliases.ts`
#### Doel
Wanneer je dezelfde type-definitie veel gebruikt, maken type aliases je code **schoner en herbruikbaarder**. Dit is als een "naam geven" aan je types.
#### Wat je gaat leren
- Type aliases: `type Name = Type`
- Wanneer aliassen beter zijn dan inline types
- Type aliases voor complexe types
#### De Challenge
Je code herhaalt dezelfde type-definitie overal:
```typescript
// ❌ Overal schreef je dit:
function getUser(id: string | number): { name: string; age: number } { }
function updateUser(id: string | number, data: { name: string; age: number }): void { }
function deleteUser(id: string | number): { name: string; age: number } { }
// ✅ Beter: maak type aliases!
type UserId = string | number;
type UserData = { name: string; age: number };
// En hergebruik ze:
function getUser(id: UserId): UserData { }
function updateUser(id: UserId, data: UserData): void { }
function deleteUser(id: UserId): UserData { }
```
Jouw taak: Identificeer repetitieve type-definitions en maak aliassen.
#### Hints
- 💡 Syntax: `type NameOfType = ActualType;`
- 💡 Aliassen beginnen meestal met een HOOFDLETTER
- 💡 Dit voorkomt "copy-paste type-fouten"
---
### 🚪 Kamer 7: Functies Typen
**Moeilijkheid:** ⭐⭐⭐ Moeilijk
**Bestand:** `src/kamer7-functies.ts`
#### Doel
Dit is waar het serieus wordt. Je gaat **functie parameters en return types** volledig typen. Dit is essentieel voor grote codebases.
#### Wat je gaat leren
- Function parameter types: `function foo(x: Type) { }`
- Return types: `function foo(): ReturnType { }`
- Callback types: functies die functies ontvangen
- Arrow function syntax typen
#### De Challenge
Je krijgt niet-getypte functies:
```typescript
// ❌ Geen types!
function add(a, b) {
return a + b;
}
function filterNumbers(items, condition) {
return items.filter(condition);
}
const greet = (name) => {
return `Hello, ${name}!`;
};
// ✅ Jouw taak: Maak ze VOLLEDIG getypt!
function add(a: number, b: number): number {
return a + b;
}
function filterNumbers(items: number[], condition: (n: number) => boolean): number[] {
return items.filter(condition);
}
const greet = (name: string): string => {
return `Hello, ${name}!`;
};
```
Sommige functies hebben **callbacks** (functies als parameters):
```typescript
function runTwice(fn: ?): void {
fn();
fn();
}
// Wat is het type van `fn`? Een functie die geen parameters neemt!
```
#### Hints
- 💡 Altijd annotate: parameters EN return type
- 💡 Arrow functions: `(param: Type): ReturnType => { }`
- 💡 Callback types: `(param: Type) => ReturnType`
- 💡 Geen parameters? `() => ReturnType`
---
### 🚪 Kamer 8: Boss Room 🏆
**Moeilijkheid:** ⭐⭐⭐ Moeilijk
**Bestand:** `src/kamer8-boss.ts`
#### Doel
Dit is het **finale level**. Je combineert ALLES wat je hebt geleerd in één groot project. Dit is een echte, praktische TypeScript-scenario.
#### Wat je gaat leren
- Integratie van alle vorige concepts
- Realistische type-design
- Denken in termen van "veilige types"
#### De Challenge
Je krijgt een onvolledig systeem, bijv. een "Blogplatform" of "Takenmanager". Je taak:
1. **Schrijf alle interfaces** voor de data structures
2. **Type alle functies** volledig
3. **Gebruik union types, aliases, optionals** waar nodig
4. **Zorg dat alles samenwerkt**
Voorbeeld:
```typescript
// ❌ Gegeven (ongetypt):
class BlogManager {
posts = [];
addPost(title, content, author) {
// ...
}
getPostsByAuthor(author) {
// ...
}
deletePost(postId) {
// ...
}
}
// ✅ Jouw taak: Maak het volledig getypt
interface Post {
id: string;
title: string;
content: string;
author: string;
createdAt: Date;
}
type PostId = string;
class BlogManager {
posts: Post[] = [];
addPost(title: string, content: string, author: string): Post {
// ...
}
getPostsByAuthor(author: string): Post[] {
// ...
}
deletePost(postId: PostId): boolean {
// ...
}
}
```
Dit is realistisch werk. Je ziet hoe types een compleet systeem kunnen gidsen.
#### Hints
- 💡 Begin met de interfaces voor je data
- 💡 Type dan je functies
- 💡 Controleer constant met `npm run check`
- 💡 Dit is moeilijk, maar jij gaat het redden!
---
## Hoe Track Je Je Voortgang?
### Command 1: Check je status
```bash
npm run check
```
Dit toont je ALLE kamers en hun status:
```
✅ Kamer 1: Basic Types
✅ Kamer 2: Type Inference
❌ Kamer 3: Interfaces [3 errors]
❌ Kamer 4: Optional Props [1 error]
⏳ Kamer 5+: Nog niet gestart
```
Run dit regelmatig — het is je "scorebord"!
### Command 2: Ontsnapt!
```bash
npm run escape
```
Runnen dit als ALLES ✅ is. Je project compileert en geeft je de **escape code**:
```
🔐 ALLE KAMERS ONTSNAPT! 🔐
Je escape code is: TS2024-TYPES-MASTER-42
Gefeliciteerd! Je bent een TypeScript type-master!
```
---
## Tips & Tricks
### 1⃣ Gebruik Cursor's AI (gratis!)
- **Ctrl+K** (of **Cmd+K** op Mac): Open Cursor's code editor
- **Ctrl+L**: Highlight code en vraag om hulp
- **Ctrl+I**: Inline code generation
Voorbeeld:
```
"Ik heb een interface User met name, email, en optioneel phone.
Schrijf een functie getUser(id: string): User"
```
### 2⃣ Hover voor Error Messages
Wanneer je rode squiggles ziet, **hover** erover. TypeScript zegt je exact wat verkeerd is.
### 3⃣ Bekijk Type Definitie
**Ctrl+Click** (of **Cmd+Click**) op een type om te zien hoe het gedefinieerd is.
### 4⃣ Probeer EERST Zelf
- Lees de comment-hints in het bestand
- Denk na: "Wat is het juiste type?"
- Pas het aan
- Check met `npm run check`
Pas dan naar Cursor Chat als je stuck bent.
### 5⃣ Lees de Comments!
Elk bestand bevat **hints in comments**:
```typescript
// TODO: Type deze parameter als string | number
function process(value) { }
// TIP: Denk: moet dit ALTIJD aanwezig zijn?
interface Config {
debug: boolean;
}
```
---
## Wat Als Je Vastzit?
### Stap 1: Lees de Error
```
error TS2322: Type 'string' is not assignable to type 'number'
```
Dit zegt: je probeert een string in een number-veld te stoppen. Fout type!
### Stap 2: Check de Hints
- Lees comments in je bestand
- Hover over errors
- Kijk naar omringende code
### Stap 3: Gebruik Cursor Chat
- Open **Cursor Chat** (Cmd+L)
- Vraag: "Wat is het juiste type voor deze functie?"
- Cursor helpt je (geen spoilers, maar guidance)
### Stap 4: Documentatie
- [TypeScript Handbook](https://www.typescriptlang.org/docs/) (Engels)
- Kijk op Canvas voor Nederlands uitleg
---
## Bonus Challenges (Extra Sterren! ⭐)
Wanneer je alle 8 kamers hebt opgelost (en de escape code hebt!), kun je nog meer doen:
### Bonus Kamer 9: Custom Domain
Verzin een eigen domein dat je interessant vindt (bijv. Recipes, Music Playlist, Game Inventory) en schrijf:
- 3-5 interfaces
- 2-3 getypte functies
- Minstens 1 union type of type alias
### Bonus Kamer 10: Generics Preview
Generics zijn "types voor types". Dit is Les 5, maar je kunt vooruitlopen:
```typescript
// Generic functie: werkt met elk array-type
function getFirst<T>(items: T[]): T {
return items[0];
}
const firstString = getFirst(["a", "b"]); // string
const firstNumber = getFirst([1, 2, 3]); // number
```
Schrijf 2-3 generische functies en test ze.
---
## Deliverables
Wanneer je klaar bent:
### 1. Screenshot van Escape Code
```bash
npm run escape
```
Maak een screenshot van je output (inclusief de escape code!).
### 2. Post in Teams
- Ga naar het **Les 4 channel** op Teams
- Post je screenshot
- Typ je escape code in de chat
- Voeg een kort comment toe: wat was het moeilijkste? (1-2 zinnen)
### 3. Bonus: Show & Tell
Heb je de bonus challenges gedaan? Post die ook! (screenshot of GitHub link)
---
## Wat Je Hebt Geleerd
Na deze escaperoom begrijp je:
**Basic Types**: string, number, boolean, arrays
**Type Inference**: wanneer TypeScript types zelf kan afleiden
**Interfaces**: objecten typen
**Optionals**: properties die misschien aanwezig zijn
**Union Types**: "dit ÓF dat"
**Type Aliases**: types hergebruiken
**Function Types**: parameters en returns volledig typen
**Integration**: alles samen in real code
Dit zijn de **essentiële fundamenten** van TypeScript. Hiermee kun je veilige, schone code schrijven die zichzelf documenteert.
---
## FAQ
**V: Mag ik ChatGPT gebruiken?**
A: Ja, maar probeer EERST zelf. ChatGPT voert je door, Cursor Chat leert je.
**V: Wat als ik een kamer echt niet snap?**
A: (1) Kijk de video-uitleg voor Les 4 opnieuw, (2) Vraag de docent, (3) Werk met een classmate samen.
**V: Hoe lang duurt dit?**
A: 2-3 uur voor de basis kamers. Bonus challenges: +1 uur.
**V: Is dit onderdeel van mijn cijfer?**
A: Ja! De escape code bewijst dat je het geleerd hebt. Post hem voor volle punten.
**V: Kan ik offline werken?**
A: Ja! Download, install `npm install`, en werk offline. Controleer later je escape code.
---
## Je Bent Klaar voor Les 5! 🎓
Als je alle kamers hebt ontsnapt, ben je klaar voor:
- **Generics** (Les 5)
- **Classes & Advanced Types** (Les 6)
- **Real TypeScript Projects** (Les 7+)
Veel succes, en geniet van de escaperoom! 🔓

View File

@@ -0,0 +1,270 @@
# Huiswerk Les 4: JavaScript naar TypeScript Converter
## Wat ga je doen?
In deze les heb je geleerd hoe TypeScript je code veiliger maakt met types. Nu ga je dat in de praktijk brengen! Je krijgt een JavaScript project met utility functies voor een e-commerce systeem. Jouw taak: **alles omzetten naar TypeScript zonder `any` types te gebruiken**.
Dit huiswerk bereidt je voor op Les 5, waar je deze getypeerde functies met React gaat combineren.
---
## Setup
1. **Download** `les4-huiswerk-js-converter.zip` van Teams
2. **Pak uit** en open de folder in Cursor/VS Code
3. **Installeer dependencies**: `npm install`
4. **Bekijk** de JavaScript bestanden in `src/`
5. **Begin omzetten!**
De folder ziet er zo uit:
```
les4-huiswerk-js-converter/
├── src/
│ ├── users.js
│ ├── products.js
│ ├── orders.js
│ └── utils.js
├── __tests__/
│ ├── users.test.ts
│ ├── products.test.ts
│ ├── orders.test.ts
│ └── utils.test.ts
├── tsconfig.json
├── package.json
└── README.md
```
---
## De Bestanden
### Bestand 1: `src/users.ts`
Je moet `users.js` omzetten naar `users.ts`.
**Functies die je zult tegenkomen:**
- `createUser(name, email, age)` — maakt een nieuwe user aan
- `findUser(users, id)` — zoekt een user op id
- `updateUser(users, id, updates)` — update user gegevens
- `filterActiveUsers(users)` — geeft alle actieve users terug
**Wat je moet doen:**
1. Maak een `User` interface met: `id`, `name`, `email`, `age`, `isActive` (boolean)
2. Zorg dat de `createUser` functie het juiste type teruggeeft
3. Type alle parameters en return types volledig
4. Geen `any`!
**Hint:** Kijk in de tests hoe `User` wordt gebruikt — dat zegt je veel over de verwachte types.
---
### Bestand 2: `src/products.ts`
Je moet `products.js` omzetten naar `products.ts`.
**Functies die je zult tegenkomen:**
- `createProduct(name, price, category)` — maakt een nieuw product aan
- `applyDiscount(product, discountPercent)` — past korting toe
- `getExpensiveProducts(products, minPrice)` — filtert dure producten
- `formatPrice(price)` — formatteert prijs als string
**Wat je moet doen:**
1. Maak een `Product` interface met: `id`, `name`, `price`, `category`, `discount` (optioneel)
2. Maak een **union type** voor category: `"electronics" | "clothing" | "books" | "other"`
3. Type alle functies compleet
4. De `applyDiscount` functie geeft een nieuw object terug (mutation voorkomen)
5. Geen `any`!
**Extra uitdaging:** Sommige producten hebben misschien geen discount. Maak dit veld optioneel met `?`
---
### Bestand 3: `src/orders.ts`
Je moet `orders.js` omzetten naar `orders.ts`.
**Functies die je zult tegenkomen:**
- `createOrder(user, products)` — maakt een order aan
- `calculateTotal(order)` — berekent totale prijs
- `getOrderStatus(order)` — geeft de status terug
- `getOrdersByUser(orders, userId)` — filtert orders per user
**Wat je moet doen:**
1. Maak een `Order` interface met: `id`, `userId`, `products` (array), `total`, `status`, `createdAt`
2. Maak een **union type** voor OrderStatus: `"pending" | "processing" | "shipped" | "delivered"`
3. De `userId` in Order moet verwijzen naar de User die je in bestand 1 hebt gemaakt
4. `products` in Order moet een array van Product zijn
5. Type alle functies compleet
6. Geen `any`!
**Samenwerking:** Je Orders werken met Users en Products van de vorige bestanden!
---
### Bestand 4: `src/utils.ts`
Je moet `utils.js` omzetten naar `utils.ts`. Dit bestand heeft wat moeilijkere type challenges.
**Functies die je zult tegenkomen:**
- `formatDate(date)` — formatteert een Date naar "DD-MM-YYYY"
- `generateId()` — genereert een willekeurige string ID
- `validateEmail(email)` — checkt of email geldig is (return boolean)
- `sortBy(items, key)` — sorteert een array op een bepaalde eigenschap
**Wat je moet doen:**
1. `formatDate` ontvangt een `Date` en geeft een `string` terug
2. `generateId` geeft altijd een `string` terug
3. `validateEmail` geeft een `boolean` terug
4. `sortBy` is het lastigste! Dit is waar **generics** om de hoek komen kijken (voorbereiding Les 5)
- `sortBy` moet werken met *elk* soort array
- De functie signature zou iets als `function sortBy<T>(items: T[], key: keyof T): T[]` moeten zijn
- Dit zeggen we in Les 5 meer over, maar je mag het nu al proberen!
**Geen `any`!**
---
## Vereisten
Zorg dat je aan álle punten voldoet:
-**Geen `any` types** — serieus, zelfs niet voor "snel omzetten"
-**Geen `// @ts-ignore` comments** — verstop de problemen niet
-**Alle functies volledig getypt** — parameters EN return types
-**Interfaces voor alle objecten** — User, Product, Order
-**Union types waar logisch** — ProductCategory en OrderStatus
-**Optional properties waar nodig** — velden met `?`
-**`npm run check` moet 0 errors geven** — TypeScript compiler akkoord
---
## Verificatie
Als je klaar bent, run je deze commands:
```bash
# Controleer TypeScript errors (moet 0 tonen)
npm run check
# Run de tests (alle tests moeten slagen)
npm test
```
De tests zijn al geschreven in TypeScript! Ze checken of jouw types correct zijn. Als tests mislukken, kijk dan naar de foutmelding — die zal je helpen.
---
## Tips & Tricks
**1. Begin met interfaces**
Definieer eerst de shapes van je data. Dan schrijf je veel makkelijker de functies.
```typescript
interface User {
id: string;
name: string;
email: string;
age: number;
isActive: boolean;
}
```
**2. Kijk naar hoe functies GEBRUIKT worden**
Open de test files in `__tests__/` — die laten zien hoe je types moeten werken. Tests zijn je "spec"!
**3. Gebruik Cursor voor hints**
Cursor geeft je hover-tips. Hover over een functie en zie wat het verwacht. Maar probeer eerst zelf!
**4. Union types zijn duidelijker dan strings**
Dit:
```typescript
type OrderStatus = "pending" | "processing" | "shipped" | "delivered";
```
Is veel beter dan:
```typescript
status: string;
```
Waarom? TypeScript geeft je autocomplete en warnt je als je een verkeerde status invult.
**5. Optional properties met `?`**
Niet alles is verplicht. Producten hebben misschien geen korting:
```typescript
interface Product {
id: string;
name: string;
price: number;
discount?: number; // optioneel!
}
```
**6. Ga stap voor stap**
- Zet eerst alles om naar `.ts` files
- Type dan één bestand af
- Zorg dat `npm run check` nul errors toont
- Ga dan naar volgende bestand
---
## Bonus Challenges
Als je voort bent en meer wilt leren:
**Bonus 1: JSDoc Comments**
Voeg JSDoc comments toe aan je interfaces. Dit geeft developers (inclusief jezelf later) hulp:
```typescript
/**
* Vertegenwoordigt een gebruiker in het systeem
* @property id - Unieke identifier
* @property name - Volledige naam van de gebruiker
* @property email - E-mailadres (moet uniek zijn)
* @property age - Leeftijd in jaren
* @property isActive - Of de account actief is
*/
interface User {
id: string;
name: string;
email: string;
age: number;
isActive: boolean;
}
```
**Bonus 2: Barrel Export**
Maak een `src/index.ts` die alles exporteert:
```typescript
export { User, createUser, findUser, updateUser, filterActiveUsers } from './users';
export { Product, createProduct, applyDiscount, getExpensiveProducts, formatPrice } from './products';
export { Order, createOrder, calculateTotal, getOrderStatus, getOrdersByUser } from './orders';
export { formatDate, generateId, validateEmail, sortBy } from './utils';
```
**Bonus 3: Generics in sortBy**
Probeer `sortBy` echt generiek te maken. Dit is Les 5 materiaal, maar je mag het nu al proberen! Hint: je hebt `<T>` nodig en `keyof T`.
---
## Inleveren
1. **Push naar GitHub** — je repositorywaar je al aan werkt
2. **Branch:** `feature/les4-typescript-converter`
3. **Commit message:** `feat: convert JavaScript utilities to TypeScript`
4. **Deadline:** Voor het begin van Les 5
---
## Verwachte tijd
Dit huiswerk duurt ongeveer **1,5 tot 2 uur** afhankelijk van je snelheid. Niet rennen — begrijpen is belangrijker!
---
## Vragen?
- Stuck op een error? Lees het TypeScript error message goed
- Weet je de syntax van een type niet? Kijk in de lesson slides Les 4
- Denk je dat de tests fout zijn? Neem contact op!
Veel succes! 🚀

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,629 @@
# Les04 TypeScript Escape Room - Antwoordsleutel
**Moeilijkheid:** Easy → Hard
**Totale tijd:** ~2-3 uur
**Finale Escape Code:** `TYPE-SAFE-CODE-LOCK-OPEN-DOOR-FREE-DOM!`
---
## Kamer 1: Basic Types
### Wat is kapot
```typescript
let filmTitle: number = "The Matrix";
let releaseYear: string = 1999;
let isClassic: string = true;
let scores: string[] = [8.7, 9.0, 8.5];
let cast: number[] = ["Keanu Reeves", "Laurence Fishburne", "Carrie-Anne Moss"];
function calculateAverage(numbers: string[]): string {
function printFilmInfo(title: string, year: number, rating: number) {
```
### De fix
```typescript
let filmTitle: string = "The Matrix";
let releaseYear: number = 1999;
let isClassic: boolean = true;
let scores: number[] = [8.7, 9.0, 8.5];
let cast: string[] = ["Keanu Reeves", "Laurence Fishburne", "Carrie-Anne Moss"];
function calculateAverage(numbers: number[]): number {
let total = 0;
for (const number of numbers) {
total += number;
}
return total / numbers.length;
}
function printFilmInfo(title: string, year: number, rating: number): void {
console.log(`${title} (${year}) - Rating: ${rating}`);
}
```
### Uitleg
De variabelen hebben verkeerde type annotaties toegewezen. `filmTitle` moet `string` zijn (niet `number`), `releaseYear` moet `number` zijn (niet `string`), `isClassic` moet `boolean` zijn (niet `string`), `scores` moet `number[]` zijn (niet `string[]`), en `cast` moet `string[]` zijn (niet `number[]`). De `calculateAverage` functie moet `number[]` accepteren en `number` retourneren. De `printFilmInfo` functie mist de return type annotation `: void`.
### Room Code
```
TYPE
```
---
## Kamer 2: Type Inference
### Wat is kapot
```typescript
let gameTitle: string = "Elden Ring";
let playerName = "Tarnished";
function processScores(scores: number[], callback) {
function calculate(a: number, b) {
```
### De fix
```typescript
let gameTitle = "Elden Ring";
let playerName: string = "Tarnished";
function processScores(scores: number[], callback: (s: number) => number) {
return scores.map(callback);
}
function calculate(a: number, b: number): number {
return a + b;
}
```
### Uitleg
Kamer 2 gaat om type inference en herkennen wanneer je type annotations nodig hebt. `gameTitle` heeft een expliciete type annotation `: string` die niet nodig is - TypeScript kan het afleiden uit de string literal. De `processScores` callback mist een type: het moet `(s: number) => number` zijn. De `calculate` parameter `b` mist een type (moet `number` zijn). Callback parameters MOETEN altijd expliciet getypeerd zijn, maar return types kunnen soms worden afgeleid.
### Room Code
```
SAFE
```
---
## Kamer 3: Interfaces
### Wat is kapot
De interfaces `User`, `Product`, `Address`, en `Employee` zijn niet gedefinieerd, maar worden wel gebruikt in type annotaties:
```typescript
const user1: User = { ... }
const product1: Product = { ... }
const employee: Employee = { ... }
```
### De fix
```typescript
interface User {
id: number;
name: string;
email: string;
age: number;
}
interface Product {
id: number;
name: string;
price: number;
inStock: boolean;
}
interface Address {
street: string;
city: string;
zipCode: string;
}
interface Employee {
id: number;
name: string;
address: Address;
salary: number;
}
const user1: User = {
id: 1,
name: "Alice",
email: "alice@example.com",
age: 28,
};
const product1: Product = {
id: 101,
name: "Laptop",
price: 999.99,
inStock: true,
};
const employee: Employee = {
id: 42,
name: "Bob",
address: {
street: "Main Street 123",
city: "Amsterdam",
zipCode: "1012 XY",
},
salary: 50000,
};
```
### Uitleg
Interfaces moeten worden gedefinieerd voordat je ze als type annotations kunt gebruiken. `Address` is genest in `Employee`, dus moet als aparte interface worden gedefinieerd. Dit demonstreert object compositie: `Employee` bevat een `Address` object als property.
### Room Code
```
CODE
```
---
## Kamer 4: Optional Properties
### Wat is kapot
```typescript
interface Customer {
id: number;
name: string;
email: string;
phoneNumber: string; // Maar customer1 heeft dit niet!
}
interface Film {
id: number;
title: string;
imdbScore: number;
description: string; // Maar film1 heeft dit niet!
releaseDate: number; // Maar film1 heeft dit niet!
}
function contactCustomer(customer: Customer): string {
return `Call ${customer.name} at ${customer.phoneNumber}`;
// Geen check of phoneNumber undefined is!
}
function printFilmDetails(film: Film): void {
console.log(`${film.title} (${film.releaseDate})`);
// Geen check of releaseDate undefined is!
console.log(`Description: ${film.description}`);
// Geen check of description undefined is!
}
```
### De fix
```typescript
interface Customer {
id: number;
name: string;
email: string;
phoneNumber?: string;
}
interface Film {
id: number;
title: string;
imdbScore: number;
description?: string;
releaseDate?: number;
}
function contactCustomer(customer: Customer): string {
return `Call ${customer.name} at ${customer.phoneNumber || "no phone"}`;
}
function printFilmDetails(film: Film): void {
console.log(`${film.title} (${film.releaseDate || "unknown year"})`);
console.log(`Description: ${film.description || "No description"}`);
console.log(`IMDB: ${film.imdbScore}`);
}
function safePrintCustomer(customer: Customer): void {
let contact = `${customer.name} (${customer.email})`;
if (customer.phoneNumber) {
contact += ` - ${customer.phoneNumber}`;
}
console.log(contact);
}
function safeFilmInfo(film: Film): string {
let info = `${film.title} - ${film.imdbScore}/10`;
if (film.releaseDate) {
info += ` (${film.releaseDate})`;
}
if (film.description) {
info += ` - ${film.description}`;
}
return info;
}
```
### Uitleg
De `?` markeren optionele properties (kunnen `undefined` zijn). Functies die optionele velden gebruiken, moeten controleren of ze bestaan voordat ze worden gebruikt. Zonder deze checks krijg je type errors.
### Room Code
```
LOCK
```
---
## Kamer 5: Union Types
### Wat is kapot
```typescript
const order1: Order = {
id: 1,
status: "processing", // Niet in union!
amount: 99.99,
paymentMethod: "paypal_pro", // Niet in union!
};
const user1: User = {
id: 1,
name: "Carlos",
theme: "system", // Niet in union!
orders: [order1],
};
```
### De fix
```typescript
type OrderStatus = "pending" | "shipped" | "delivered";
type Theme = "light" | "dark" | "auto";
type PaymentMethod = "credit_card" | "paypal" | "bank_transfer";
const order1: Order = {
id: 1,
status: "shipped", // ✓ Geldige waarde
amount: 99.99,
paymentMethod: "paypal", // ✓ Geldige waarde
};
const user1: User = {
id: 1,
name: "Carlos",
theme: "dark", // ✓ Geldige waarde
orders: [order1],
};
```
### Uitleg
Union types (`|`) beperken waarden tot specifieke opties. `status: "processing"` is geen geldige waarde uit de union. `paymentMethod: "paypal_pro"` is ook niet geldig (moet `"paypal"` zijn). `theme: "system"` is niet geldig (moet een van `"light" | "dark" | "auto"` zijn). De bestaande type aliases in het bestand zijn correct, dus je hoeft ze alleen maar in plaats van ongeldige waarden te gebruiken.
### Room Code
```
OPEN
```
---
## Kamer 6: Type Aliases
### Wat is kapot
```typescript
const developer1: Developer = { ... } // Developer type bestaat niet
const developer2: Developer = { ... }
const apiResponse1: ApiResponse = { ... } // ApiResponse type bestaat niet
const apiResponse2: ApiResponse = { ... }
const serverConfig: ServerConfig = { ... } // ServerConfig type bestaat niet
callback: DeveloperCallback // DeveloperCallback type bestaat niet
```
### De fix
```typescript
type Developer = {
id: number;
name: string;
email: string;
programmingLanguages: string[];
yearsOfExperience: number;
};
type ApiResponse = {
success: boolean;
data: any;
message?: string;
};
type ServerConfig = {
hostname: string;
port: number;
ssl: boolean;
timeout?: number;
};
type DeveloperCallback = (dev: Developer) => void;
const developer1: Developer = {
id: 1,
name: "Alice",
email: "alice@dev.com",
programmingLanguages: ["TypeScript", "JavaScript", "Python"],
yearsOfExperience: 5,
};
const developer2: Developer = {
id: 2,
name: "Bob",
email: "bob@dev.com",
programmingLanguages: ["Rust", "Go"],
yearsOfExperience: 8,
};
const apiResponse1: ApiResponse = {
success: true,
data: { count: 42 },
};
const apiResponse2: ApiResponse = {
success: false,
data: {},
message: "Not found",
};
function createConfig(options: ServerConfig): void {
console.log(`Connecting to ${options.hostname}:${options.port}`);
}
const serverConfig: ServerConfig = {
hostname: "localhost",
port: 3000,
ssl: false,
timeout: 5000,
};
function processDevelopers(
developers: Developer[],
callback: DeveloperCallback
): void {
developers.forEach(callback);
}
```
### Uitleg
Type aliases (`type`) geven namen aan lange inline type definities. Dit volgt het DRY (Don't Repeat Yourself) principe. In plaats van dezelfde structuur steeds opnieuw in te typen, definieer je het eenmalig als `type Developer`. Dit maakt code leesbaar en gemakkelijk onderhoudbaar.
### Room Code
```
DOOR
```
---
## Kamer 7: Function Types
### Wat is kapot
```typescript
function transformArray<T, U>(items: T[], callback: Transformer<T, U>): U[] {
function validateField(validators: Validation[], value: string) {
// Return type ontbreekt!
function createErrorHandler(callback: Validator): EventHandler {
return (error: any) => { // error type is niet correct
function createEventDispatcher(handlers: EventHandler[]): EventHandler {
return (event: any) => { // event type is niet correct
function filter<T>(items: T[], predicate: Transformer<T, boolean>): T[] {
```
### De fix
```typescript
type Validator = (value: string) => boolean;
type Transformer<T, U> = (item: T) => U;
type EventHandler = (event: unknown) => void;
function transformArray<T, U>(items: T[], callback: Transformer<T, U>): U[] {
return items.map(callback);
}
function validateField(validators: Validation[], value: string): { valid: boolean; error?: string } {
for (const validator of validators) {
if (!validator.validator(value)) {
return {
valid: false,
error: validator.errorMessage,
};
}
}
return {
valid: true,
};
}
function createErrorHandler(callback: (error: any) => void): EventHandler {
return (error: unknown) => {
console.log(`Error: ${error}`);
if (typeof error === 'object' && error !== null && 'message' in error) {
callback(error);
}
};
}
function createEventDispatcher(handlers: EventHandler[]): EventHandler {
return (event: unknown) => {
handlers.forEach((handler) => handler(event));
};
}
function filter<T>(items: T[], predicate: (item: T) => boolean): T[] {
return items.filter(predicate);
}
```
### Uitleg
`validateField` mist de return type annotation (moet zijn `{ valid: boolean; error?: string }`). De `createErrorHandler` functie accepteert een callback maar die callback type klopt niet goed met hoe het wordt gebruikt. `createEventDispatcher` is een higher-order function (returnt een function) dus moet dat correct getypeerd zijn. De `filter` functie zou `(item: T) => boolean` als predicate moeten hebben, niet `Transformer<T, boolean>`.
### Room Code
```
FREE
```
---
## Kamer 8: Boss Room
### Wat is kapot
```typescript
const movie1: Movie = {
id: 1,
title: "Inception",
genre: "mysterious", // Niet in Genre union!
releaseYear: 2010,
director: nolan,
status: "released",
imdbScore: 8.8,
reviews: [review1, review2],
};
const movie2: Movie = {
id: 2,
title: "E.T.",
genre: "sci-fi",
releaseYear: 1982,
director: spielberg,
status: "complete", // Niet in MovieStatus union!
reviews: [review1],
};
```
### De fix
```typescript
type Genre = "action" | "drama" | "sci-fi" | "comedy" | "horror";
type Rating = 1 | 2 | 3 | 4 | 5;
type MovieStatus = "in_development" | "released" | "cancelled";
interface Director {
id: number;
name: string;
films: string[];
}
interface MovieReview {
id: number;
reviewer: string;
rating: Rating;
comment: string;
date?: string;
}
interface Movie {
id: number;
title: string;
genre: Genre;
releaseYear: number;
director: Director;
status: MovieStatus;
imdbScore?: number;
reviews?: MovieReview[];
budget?: number;
}
type MovieLibrary = {
movies: Movie[];
totalCount: number;
lastUpdated?: string;
};
const movie1: Movie = {
id: 1,
title: "Inception",
genre: "sci-fi", // ✓ Geldige Genre
releaseYear: 2010,
director: nolan,
status: "released",
imdbScore: 8.8,
reviews: [review1, review2],
};
const movie2: Movie = {
id: 2,
title: "E.T.",
genre: "sci-fi",
releaseYear: 1982,
director: spielberg,
status: "released", // ✓ Geldige MovieStatus
reviews: [review1],
};
function filterMovies(movies: Movie[], predicate: (m: Movie) => boolean): Movie[] {
return movies.filter(predicate);
}
function calculateAverageScore(movies: Movie[]): number {
const scores = movies
.filter((m: Movie) => m.imdbScore !== undefined)
.map((m: Movie) => m.imdbScore as number);
if (scores.length === 0) return 0;
const total = scores.reduce((acc: number, score: number) => acc + score, 0);
return total / scores.length;
}
function generateReport(library: MovieLibrary): string {
return (
`Movies in library: ${library.movies.length}\n` +
`Total: ${library.totalCount}\n` +
`Last updated: ${library.lastUpdated || "unknown"}`
);
}
function findMoviesByDirector(movies: Movie[], director: Director): Movie[] {
return movies.filter((m) => m.director.id === director.id);
}
function isHighQualityRelease(movie: Movie): boolean {
return (
movie.status === "released" &&
movie.imdbScore !== undefined &&
movie.imdbScore >= 7
);
}
```
### Uitleg
Dit is het finale level! `genre: "mysterious"` is geen geldige `Genre` (moet één van `"action" | "drama" | "sci-fi" | "comedy" | "horror"` zijn). `status: "complete"` is geen geldige `MovieStatus` (moet één van `"in_development" | "released" | "cancelled"` zijn). Alle interfaces en type aliases moeten worden gedefinieerd. De functies moeten correct getypeerd zijn, inclusief proper handling van optionele `imdbScore` velden met undefined checks.
### Room Code
```
DOM!
```
---
## ESCAPE CODE
De complete escape code komt samen van alle kamer codes in volgorde:
1. **Kamer 1 (Basic Types):** TYPE
2. **Kamer 2 (Type Inference):** SAFE
3. **Kamer 3 (Interfaces):** CODE
4. **Kamer 4 (Optional Properties):** LOCK
5. **Kamer 5 (Union Types):** OPEN
6. **Kamer 6 (Type Aliases):** DOOR
7. **Kamer 7 (Function Types):** FREE
8. **Kamer 8 (Boss Room):** DOM!
```
TYPE-SAFE-CODE-LOCK-OPEN-DOOR-FREE-DOM!
```
Betekenis: "Type Safe Code Lock Open Door Freedom!" - Je code is veilig, je bent vrij van runtime errors!

View File

@@ -0,0 +1,562 @@
# Les 4: TypeScript Fundamentals - Huiswerk ANTWOORDEN
Deze antwoordsleutel toont de volledige conversie van JavaScript naar TypeScript voor het huiswerk van Les 4. Voor elk bestand wordt een interface, type definitions en de complete TypeScript-implementatie getoond.
---
## 1. users.ts - Gebruikersbeheer
### Origineel JavaScript (users.js)
De originele JavaScript-versie bevat vijf functies voor gebruikersbeheer:
- `createUser()`: Maakt een nieuwe gebruiker aan met unieke ID en timestamp
- `findUserByEmail()`: Zoekt een gebruiker op emailadres
- `updateUser()`: Past gebruikerseigenschappen aan
- `filterActiveUsers()`: Filtert alleen actieve gebruikers
- `deactivateUser()`: Deactiveert een gebruiker
### Complete TypeScript Conversie
```typescript
// src/users.ts
/**
* User interface - Definieert de structuur van een gebruikersobject
*/
interface User {
id: string;
name: string;
email: string;
age: number;
isActive: boolean;
createdAt: Date;
}
/**
* Maakt een nieuwe gebruiker aan
* @param name - De naam van de gebruiker
* @param email - Het emailadres van de gebruiker
* @param age - De leeftijd van de gebruiker
* @returns Een nieuw User-object
*/
function createUser(name: string, email: string, age: number): User {
return {
id: Math.random().toString(36).substr(2, 9),
name,
email,
age,
isActive: true,
createdAt: new Date()
};
}
/**
* Zoekt een gebruiker op emailadres
* @param users - Array van gebruikers
* @param email - Het emailadres om naar te zoeken
* @returns De gevonden User, of null als niet gevonden
*/
function findUserByEmail(users: User[], email: string): User | null {
return users.find(user => user.email === email) || null;
}
/**
* Werkt gebruikerseigenschappen bij
* @param user - De originele gebruiker
* @param updates - Gedeeltelijke updates (Partial<User>)
* @returns De bijgewerkte User
*/
function updateUser(user: User, updates: Partial<User>): User {
return { ...user, ...updates };
}
/**
* Filtert alleen actieve gebruikers
* @param users - Array van gebruikers
* @returns Array van actieve gebruikers
*/
function filterActiveUsers(users: User[]): User[] {
return users.filter(user => user.isActive);
}
/**
* Deactiveert een gebruiker
* @param user - De gebruiker om te deactiveren
* @returns De gebruiker met isActive = false
*/
function deactivateUser(user: User): User {
return { ...user, isActive: false };
}
export { createUser, findUserByEmail, updateUser, filterActiveUsers, deactivateUser };
export type { User };
```
### Sleutelbeslissingen bij TypeScript Conversie
1. **User Interface**: Een interface is gedefinieerd die alle properties van een gebruiker typeert. Dit zorgt voor type-safety en autocomplete.
2. **Functie Parameters**: Alle parameters zijn voorzien van expliciete TypeScript-typen:
- `name: string`, `email: string`, `age: number` voor `createUser()`
- `users: User[]` voor arrays van gebruikers
3. **Return Types**: Alle functies hebben expliciete return types:
- `createUser()` retourneert `User`
- `findUserByEmail()` retourneert `User | null` (union type voor null-safety)
- `filterActiveUsers()` en `updateUser()` retourneren `User[]` respectievelijk `User`
4. **Partial<User> Type**: De `updateUser()` functie accepteert `Partial<User>` omdat niet alle eigenschappen hoeven te worden bijgewerkt. Dit is een built-in TypeScript utility type.
5. **Export**: Zowel functies als het User type worden geëxporteerd voor hergebruik in andere bestanden.
---
## 2. products.ts - Productbeheer
### Origineel JavaScript (products.js)
De JavaScript-versie bevat:
- `CATEGORIES`: Constante array met geldige categorieën
- `createProduct()`: Maakt een nieuw product aan met validatie
- `applyDiscount()`: Pas een kortingspercentage toe
- `getExpensiveProducts()`: Filtert producten op minimale prijs
- `formatPrice()`: Formatteert een prijs met valutasymbool
- `rateProduct()`: Voegt een rating toe (1-5)
### Complete TypeScript Conversie
```typescript
// src/products.ts
/**
* Union type voor productcategorieën
*/
type Category = 'electronics' | 'clothing' | 'food' | 'books' | 'sports';
/**
* Product interface - Definieert de structuur van een productobject
*/
interface Product {
id: string;
name: string;
price: number;
category: Category;
description: string | null;
inStock: boolean;
rating: number | null;
}
/**
* Geldige productcategorieën
*/
const CATEGORIES: Category[] = ['electronics', 'clothing', 'food', 'books', 'sports'];
/**
* Maakt een nieuw product aan
* @param name - Productnaam
* @param price - Productprijs
* @param category - Productcategorie (moet in CATEGORIES zitten)
* @param description - Optionele productbeschrijving
* @returns Een nieuw Product-object
* @throws Error als categorie ongeldig is
*/
function createProduct(
name: string,
price: number,
category: Category,
description?: string
): Product {
if (!CATEGORIES.includes(category)) {
throw new Error(`Invalid category: ${category}`);
}
return {
id: Math.random().toString(36).substr(2, 9),
name,
price,
category,
description: description || null,
inStock: true,
rating: null
};
}
/**
* Passe een kortingspercentage op een product toe
* @param product - Het originele product
* @param percentage - Kortingspercentage (0-100)
* @returns Product met verlaagde prijs
* @throws Error als percentage buiten bereik is
*/
function applyDiscount(product: Product, percentage: number): Product {
if (percentage < 0 || percentage > 100) {
throw new Error('Discount must be between 0 and 100');
}
const discountedPrice = product.price * (1 - percentage / 100);
return { ...product, price: Math.round(discountedPrice * 100) / 100 };
}
/**
* Filtert producten op minimale prijs
* @param products - Array van producten
* @param minPrice - Minimale prijs
* @returns Array van producten met prijs >= minPrice
*/
function getExpensiveProducts(products: Product[], minPrice: number): Product[] {
return products.filter(product => product.price >= minPrice);
}
/**
* Formatteert een prijs met valutasymbool
* @param price - Het prijsbedrag
* @param currency - Valutacode ('EUR', 'USD', 'GBP')
* @returns Geformateerde prijsstring (bijv. '€19.99')
*/
function formatPrice(price: number, currency: string): string {
const currencySymbols: Record<string, string> = {
EUR: '€',
USD: '$',
GBP: '£'
};
const symbol = currencySymbols[currency] || currency;
return `${symbol}${price.toFixed(2)}`;
}
/**
* Voegt een rating toe aan een product
* @param product - Het originele product
* @param rating - Rating waarde (1-5)
* @returns Product met rating
* @throws Error als rating buiten bereik is
*/
function rateProduct(product: Product, rating: number): Product {
if (rating < 1 || rating > 5) {
throw new Error('Rating must be between 1 and 5');
}
return { ...product, rating };
}
export { createProduct, applyDiscount, getExpensiveProducts, formatPrice, rateProduct, CATEGORIES };
export type { Product, Category };
```
### Sleutelbeslissingen bij TypeScript Conversie
1. **Category Union Type**: In plaats van een willekeurige string, gebruiken we een union type `type Category = 'electronics' | 'clothing' | 'food' | 'books' | 'sports'`. Dit voorkomt ongeldige categorieën en geeft betere autocomplete in IDE's.
2. **Product Interface**: Definieert alle eigenschappen met correcte typen:
- `category: Category` in plaats van `string` (type-safe)
- `description: string | null` en `rating: number | null` voor optionele waarden
- `price: number` voor numerieke waarden
3. **CATEGORIES Type**: `const CATEGORIES: Category[]` zorgt ervoor dat de array alleen geldige categorieën bevat.
4. **Overloading Voorkomen**: De `createProduct()` functie accepteert `description?: string` (optionele parameter) in plaats van `description = null`. Dit is schoner en meer TypeScript-idiomatic.
5. **Record<string, string>**: Voor `currencySymbols` gebruiken we `Record<string, string>` in plaats van een gewone object, wat typezekerheid biedt.
6. **Validatie Types**: De functies valideren hun inputs en gooien TypeErrors met duidelijke berichten.
---
## 3. orders.ts - Orderbeheer
### Origineel JavaScript (orders.js)
De JavaScript-versie bevat:
- `createOrder()`: Maakt een nieuwe order aan
- `calculateTotal()`: Berekent de totale prijs
- `updateOrderStatus()`: Wijzigt orderstatus met validatie
- `getOrdersByUser()`: Filtert orders per gebruiker
- `getOrdersByStatus()`: Filtert orders per status
### Complete TypeScript Conversie
```typescript
// src/orders.ts
/**
* Union type voor mogelijke orderstatussen
*/
type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';
/**
* OrderItem interface - Representeert een product in een order
*/
interface OrderItem {
productId: string;
name: string;
price: number;
}
/**
* Order interface - Definieert de structuur van een orderobject
*/
interface Order {
id: string;
userId: string;
products: OrderItem[];
total: number;
status: OrderStatus;
createdAt: Date;
}
/**
* Type voor geldige statustransities
*/
type ValidTransitions = Record<OrderStatus, OrderStatus[]>;
/**
* Maakt een nieuwe order aan
* @param user - Het User-object (moet minimaal id hebben)
* @param products - Array van Product-objecten
* @returns Een nieuw Order-object met status 'pending'
*/
function createOrder(
user: { id: string },
products: Array<{ id: string; name: string; price: number }>
): Order {
return {
id: Math.random().toString(36).substr(2, 9),
userId: user.id,
products: products.map(p => ({ productId: p.id, name: p.name, price: p.price })),
total: calculateTotal(products),
status: 'pending',
createdAt: new Date()
};
}
/**
* Berekent het totaalbedrag van producten
* @param products - Array van producten met price property
* @returns Totaalbedrag
*/
function calculateTotal(products: Array<{ price: number }>): number {
return products.reduce((sum, product) => sum + product.price, 0);
}
/**
* Wijzigt de status van een order
* @param order - De originele order
* @param newStatus - De nieuwe status
* @returns Order met bijgewerkte status
* @throws Error als transactie ongeldig is
*/
function updateOrderStatus(order: Order, newStatus: OrderStatus): Order {
const validTransitions: ValidTransitions = {
pending: ['processing', 'cancelled'],
processing: ['shipped', 'cancelled'],
shipped: ['delivered'],
delivered: [],
cancelled: []
};
if (!validTransitions[order.status].includes(newStatus)) {
throw new Error(`Cannot transition from ${order.status} to ${newStatus}`);
}
return { ...order, status: newStatus };
}
/**
* Filtert orders van een specifieke gebruiker
* @param orders - Array van orders
* @param userId - De gebruikers-ID
* @returns Array van orders van die gebruiker
*/
function getOrdersByUser(orders: Order[], userId: string): Order[] {
return orders.filter(order => order.userId === userId);
}
/**
* Filtert orders op status
* @param orders - Array van orders
* @param status - De filterstatus
* @returns Array van orders met die status
*/
function getOrdersByStatus(orders: Order[], status: OrderStatus): Order[] {
return orders.filter(order => order.status === status);
}
export { createOrder, calculateTotal, updateOrderStatus, getOrdersByUser, getOrdersByStatus };
export type { Order, OrderStatus, OrderItem };
```
### Sleutelbeslissingen bij TypeScript Conversie
1. **OrderStatus Union Type**: `type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled'` zorgt ervoor dat alleen geldige statussen kunnen worden gebruikt.
2. **OrderItem Interface**: Gescheiden interface voor orderitems maakt de code modulair en leesbaar.
3. **Order Interface**: Gebruikt het `OrderStatus` type voor de status property in plaats van `string`.
4. **Flexible Parameter Types**: `createOrder()` accepteert `user: { id: string }` in plaats van volledige User-interface. Dit maakt de functie flexibel en ontkoppeld van usersbeheer.
5. **ValidTransitions Type**: `Record<OrderStatus, OrderStatus[]>` type typeert de transities-object correct. Elke status mappen naar een array van geldige volgende statussen.
6. **Generieke Product Parameter**: `calculateTotal()` accepteert `Array<{ price: number }>` wat betekent dat het werkt met elk object dat een price-property heeft.
7. **Status Filtering**: `getOrdersByStatus()` accepteert `status: OrderStatus` waardoor alleen geldige statussen kunnen worden gefilterd.
---
## 4. utils.ts - Hulpfuncties
### Origineel JavaScript (utils.js)
De JavaScript-versie bevat:
- `formatDate()`: Formatteert een Date naar DD-MM-YYYY
- `generateId()`: Genereert een willekeurige ID-string
- `validateEmail()`: Valideert e-mailadressen met regex
- `sortBy()`: Generieke functie om items te sorteren
- `groupBy()`: Generieke functie om items te groeperen
### Complete TypeScript Conversie
```typescript
// src/utils.ts
/**
* Formatteert een Date-object naar DD-MM-YYYY string
* @param date - De Date-object
* @returns Geformateerde datestring
*/
function formatDate(date: Date): string {
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
return `${day}-${month}-${year}`;
}
/**
* Genereert een willekeurige ID-string
* @returns Unieke ID-string
*/
function generateId(): string {
return Math.random().toString(36).substr(2, 9);
}
/**
* Valideert of een string een geldig e-mailadres is
* @param email - De email-string om te valideren
* @returns true als geldig, false als ongeldig
*/
function validateEmail(email: string): boolean {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
/**
* Sorteert een array van items op een specifieke property
* Generieke functie met type parameters
* @param items - Array van items om te sorteren
* @param key - De property-naam om op te sorteren
* @param direction - Sorteerrichting 'asc' of 'desc'
* @returns Gesorteerde array (original wordt niet gewijzigd)
*/
function sortBy<T extends Record<string, any>>(
items: T[],
key: keyof T,
direction: 'asc' | 'desc'
): T[] {
return [...items].sort((a, b) => {
const aValue = a[key];
const bValue = b[key];
if (direction === 'desc') {
return aValue > bValue ? -1 : 1;
}
return aValue > bValue ? 1 : -1;
});
}
/**
* Groepeert items in een object op basis van een property
* Generieke functie met type parameters
* @param items - Array van items om te groeperen
* @param key - De property-naam om op te groeperen
* @returns Object waar keys de groepwaarden zijn en values arrays van items
*/
function groupBy<T extends Record<string, any>>(
items: T[],
key: keyof T
): Record<string | number | symbol, T[]> {
return items.reduce((groups, item) => {
const value = item[key];
if (!groups[value]) {
groups[value] = [];
}
groups[value].push(item);
return groups;
}, {} as Record<string | number | symbol, T[]>);
}
export { formatDate, generateId, validateEmail, sortBy, groupBy };
```
### Sleutelbeslissingen bij TypeScript Conversie
1. **Generieke Type Parameters**:
- `<T extends Record<string, any>>` zorgt ervoor dat T elk object-type kan zijn met string-keys
- Dit maakt `sortBy()` en `groupBy()` herbruikbaar voor alle object-arrays
2. **keyof T**: In plaats van een string voor de `key` parameter, gebruiken we `keyof T`. Dit ziet er in de IDE voor dat je alleen geldige properties van T kunt selecteren.
3. **Literal Union Type voor Direction**: `direction: 'asc' | 'desc'` in plaats van `string`, wat fouten voorkomt met ongeldige richtingen.
4. **Return Types**:
- `sortBy()` retourneert `T[]` (dezelfde type als input)
- `groupBy()` retourneert `Record<string | number | symbol, T[]>`
5. **Spread Operator Preserving**: In `sortBy()` gebruiken we `[...items]` om een kopie te maken. TypeScript begrijpt dat dit een `T[]` retourneert.
6. **Type Casting**: In `groupBy()` gebruiken we `as Record<string | number | symbol, T[]>` om TypeScript te helpen begrijpen dat we een lege Record initialiseren.
7. **Non-Mutating Approach**: Beide functies wijzigen de originele array niet, wat een best practice is voor pure functions.
---
## Samenvattend: TypeScript Conversie Principes
### 1. **Interfaces voor Data Structures**
- Elk belangrijk data-object krijgt een interface (User, Product, Order)
- Interfaces documenteren de verwachte structuur en verbeteren IDE support
### 2. **Union Types voor Enumeraties**
- In plaats van willekeurige strings, gebruiken we union types:
- `type Category = 'electronics' | 'clothing' | ...`
- `type OrderStatus = 'pending' | 'processing' | ...`
- Dit voorkomt fouten en verbetert type-safety
### 3. **Generieke Types**
- Voor herbruikbare functies als `sortBy()` en `groupBy()` gebruiken we generieke parameters
- `<T extends Record<string, any>>` zorgt voor type-safety terwijl flexibiliteit behouden blijft
### 4. **Null/Undefined Handling**
- Union types met null/undefined: `string | null`, `number | null`
- Dit dwingt expliciete handling van lege waarden
### 5. **Parameter Type Hints**
- Alle parameters hebben expliciete TypeScript-typen
- Optionele parameters gebruiken `?` of `...?: Type` syntax
### 6. **Return Type Annotations**
- Alle functies hebben expliciete return type annotations
- Dit helpt compile-time fouten opsporen en documenteert intent
### 7. **keyof en Generieke Constraints**
- `keyof T` zorgt ervoor dat je alleen geldige properties kunt selecteren
- `extends Record<string, any>` constrained het type naar objecten
### 8. **Typing van Object Methods**
- `Partial<T>` voor optionele updates
- `Record<K, V>` voor type-safe object literals
- `Pick<T, Keys>` en `Omit<T, Keys>` voor subset typen
---
## Test Compatibiliteit
Alle bovenstaande TypeScript conversies zijn ontworpen om perfect te werken met de bestaande test suite:
- **users.test.ts**: Tests gebruiken `User` interface
- **products.test.ts**: Tests gebruiken `Product` interface en `Category` type
- **orders.test.ts**: Tests gebruiken `Order`, `OrderStatus` en gerelateerde typen
- **utils.test.ts**: Tests gebruiken generieke functies met impliciete type-inferentie
De TypeScript-versies behouden exact dezelfde logic en runtime-gedrag als de originele JavaScript-versies, terwijl ze de voordelen van type-safety bieden.

View File

@@ -0,0 +1,666 @@
# Les 4: TypeScript Fundamentals (Deel 1)
## Lesdetails
| Onderdeel | Details |
|-----------|---------|
| **Lessenreeks** | Les 4 van 18 |
| **Onderwerp** | TypeScript Fundamentals |
| **Curriculumdeel** | Deel 2: Technical Foundations (Les 4-9) |
| **Datum** | - |
| **Duur totaal** | 3 uur (180 minuten) |
| **Spreektijd** | ~55 minuten |
| **Hands-on** | ~75 minuten |
| **Pauze** | 15 minuten |
| **Niveau** | Beginner/Intermediate |
| **Docent** | - |
---
## Leerdoelen
Na deze les kan de student:
1. **Uitleggen** waarom TypeScript waardevol is voor developers en hoe het zich verhoudt tot JavaScript
2. **Gebruiken** van basic types: string, number, boolean, arrays en tuples
3. **Begrijpen** hoe type inference werkt en wanneer TypeScript types automatisch detecteert
4. **Schrijven** van interfaces en type aliases voor complexe objecten
5. **Toepassen** van union types en literal types in praktische situaties
6. **Implementeren** van optional properties en functies met type safety
7. **Lezen** en **oplossen** van TypeScript errors met behulp van Cursor
8. **Onderscheiden** tussen interface en type alias en weten wanneer welke te gebruiken
---
## Lesverloop
### Blok 1: Welkom & Terugblik (10 min | 09:00-09:10)
**Doel:** Studenten welkom heten, context schetsen, en vorige les evalueren
**Activiteiten:**
- Welkomslide tonen
- Korte vraag over huiswerk Les 3: "Wie heeft de Cursor-vraagstukken afgerond? Wat was lastig?"
- Feedback op Les 3 geven (tips voor beter gebruik van Cursor)
- **Overgangsmoment:** "Vandaag leren we de taal die Cursor schrijft TypeScript. Dit is wat je nodig hebt om echt met Cursor, React en Next.js te werken."
**Spreektijd:** ~5 min | **Presentatie:** ~5 min
**Slides/Materiaal:**
- Titelbanner Les 4
- Screenshot vorige les (Cursor in actie)
---
### Blok 2: Waarom TypeScript? (15 min | 09:10-09:25)
**Doel:** Motivatie en context voor TypeScript
**Theoretisch onderdeel (~10 min):**
1. **Het probleem met JavaScript:**
- Runtime errors: bugs die pas in productie ontdekt worden
- Voorbeeld: `const user = { name: "Jan" }; console.log(user.emai);` (typo, geen fout!)
- Geen type safety: functies accepteren willekeurig wat
2. **De oplossing: TypeScript:**
- Compile-time type checking (errors voorkomen *voor* je code draait)
- Betere autocomplete in IDE / Cursor
- Self-documenting code
- Beter voor AI (Cursor snapt je code beter)
3. **TypeScript in het ecosysteem:**
- Next.js: standaard TypeScript setup
- React: de industry standard (95% professionele projecten)
- Cursor: geschreven voor TypeScript developers
**Live demo (~5 min):**
- Open Cursor
- Toon JavaScript-voorbeeld met bug
- Converteer naar TypeScript
- Toon hoe TypeScript de fout aangeeft *voordat* je het draait
**Spreektijd:** ~12 min | **Live coding:** ~3 min
**Slides/Materiaal:**
- "JavaScript vs TypeScript" vergelijking
- Live demo Cursor (voorbereid)
- Code snippets JavaScript/TypeScript
---
### Blok 3: Basic Types & Type Inference (15 min | 09:25-09:40)
**Doel:** Fundamentele types begrijpen
**Theoretisch onderdeel (~10 min):**
1. **Primitieve types:**
```typescript
// Expliciet typen
const name: string = "Alice";
const age: number = 25;
const isActive: boolean = true;
// Type inference (TypeScript raadt het zelf)
const city = "Amsterdam"; // TypeScript weet: dit is string
```
2. **Arrays:**
```typescript
const numbers: number[] = [1, 2, 3];
const names: string[] = ["Alice", "Bob"];
const mixed: (string | number)[] = ["Alice", 25]; // Union type
// Generische notatie
const items: Array<number> = [1, 2, 3];
```
3. **Type inference:**
- TypeScript detecteert types uit context
- Tip: niet overal types schrijven (onnodig verbose)
- Best practice: inference gebruiken waar duidelijk, types schrijven waar complex
4. **Speciale types:**
- `any`: "ik weet niet wat dit is" (vermijden!)
- `unknown`: "veilige `any`"
- `null` en `undefined` (zelfstandige types in strikt mode)
**Live coding (~5 min):**
- Toon type inference in Cursor (hover over variabelen)
- Toon fout: `const x: number = "hello";`
- Toon hoe Cursor autocomplete helpt
**Spreektijd:** ~11 min | **Live coding:** ~4 min
**Slides/Materiaal:**
- Type-overzicht tabel
- Voorbeeldcode (met hover-screenshots)
- Common mistakes
---
### Blok 4: Interfaces & Type Aliases (15 min | 09:40-09:55)
**Doel:** Complexe structuren typen
**Theoretisch onderdeel (~10 min):**
1. **Interfaces voor objecten:**
```typescript
interface User {
id: number;
name: string;
email: string;
age?: number; // Optional
}
const user: User = {
id: 1,
name: "Alice",
email: "alice@example.com"
// age is optional
};
```
2. **Type aliases:**
```typescript
type Status = "pending" | "approved" | "rejected"; // Union type
type ID = number | string;
interface Request {
id: ID;
status: Status;
}
```
3. **Union types & literal types:**
```typescript
type ResponseType = "success" | "error" | "pending";
const response: ResponseType = "success"; // OK
// const invalid = "warning"; // Error!
```
4. **Interface vs Type:**
- Interface: voor objecten, kan extended worden, duidelijk intent
- Type: meer flexibel, ook voor primitives, union types
- In praktijk: **gebruik interface voor objecten, type voor unions**
**Live coding (~5 min):**
- Definieer een User interface in Cursor
- Toon error bij foute property
- Toon autocomplete voor interface-properties
- Refactor naar type alias
**Spreektijd:** ~11 min | **Live coding:** ~4 min
**Slides/Materiaal:**
- Interface voorbeeld
- Type alias voorbeeld
- Venn diagram: interface vs type
- Best practices tabel
---
### Blok 5: Functies & Errors (10 min | 09:55-10:05)
**Doel:** Functies typen en errors lezen
**Theoretisch onderdeel (~7 min):**
1. **Function signatures:**
```typescript
// Parameters typen
function greet(name: string): string {
return `Hello, ${name}`;
}
// Arrow function
const add = (a: number, b: number): number => a + b;
// Optional parameter
function sayHi(name?: string): void {
console.log(`Hi ${name || "stranger"}`);
}
// Return type inference
const multiply = (x: number, y: number) => x * y; // automatisch number
```
2. **Veelvoorkomende TypeScript errors:**
- `Type 'string' is not assignable to type 'number'`
- `Property 'xxx' does not exist on type 'yyy'`
- `Argument of type 'string' is not assignable to parameter of type 'number'`
- Hoe te lezen: "TypeScript zegt dat X niet past in Y"
3. **Cursor helpt:**
- Error messages klikken = instant fix suggestion
- Hover = type info
- Autocomplete voorkomt errors
**Live coding (~3 min):**
- Definieer functie met foute parameter-types
- Toon error
- Fix met Cursor quick fix
**Spreektijd:** ~8 min | **Live coding:** ~2 min
**Slides/Materiaal:**
- Function type syntax cheatsheet
- Error message breakdown poster
- Quick fix voorbeelden
---
### Blok 6: Hands-On Intro (5 min | 10:05-10:10)
**Doel:** Studenten klaar zetten voor praktijk
**Activiteiten:**
1. **TypeScript Escaperoom uitleggen:**
- Structuur: 5 kamers, elke kamer is een TypeScript-puzzel
- Doel: code correct typen en bugs fixen
- Hint: de "escape code" is een reeks getallen (niet het doel, maar de bewijsvoering)
2. **Project setup:**
- Git repo klonen / files openen in Cursor
- `npm install` en `npm run build` uitvoeren
- Cursor diagnostics controleren (errors zichtbaar?)
3. **Eerste stappen:**
- Open kamer 1 (index.ts)
- Volg de comments (wat moet je typen?)
- Cursor helpt met autocomplete
**Spreektijd:** ~5 min
**Materiaal:**
- Project folder download link
- Setup instructies (uitgeprint of digitaal)
- Slack/Discord voor vragen
---
### ☕ PAUZE (10:10-10:25) | 15 minuten
**Docent checkt ondertussen:**
- Alle studenten zijn aan het programmeren
- Geen blokkades (technisch of conceptueel)
- Voorbereidingen voor vervolg
---
### Blok 7: Hands-On Deel 2 (75 min | 10:25-11:45)
**Doel:** Studenten zelfstandig laten programmeren met begeleiding
**Structuur:**
| Tijd | Checkpoint | Actie |
|------|-----------|-------|
| 10:25-10:45 | Start | Studenten werken, docent loopt rond |
| 10:45 | Check 1 | "Wie zit al bij kamer 3?" groepsconversatie |
| 11:00 | Check 2 | "Wie heeft de helft?" snelle feedback |
| 11:30 | Check 3 | "Wie heeft de escape code?" bijna klaar |
| 11:45 | Einde | Wrap-up + vooruitkijken |
**Docent-taken:**
- Ronde maken: vragen beantwoorden, hints geven
- **Niet zeggen:** "Je doet het verkeerd"
- **Wel zeggen:** "Wat zegt TypeScript? Laat die error eens zien."
- Snelle studenten: bonus challenges geven (zie "Bonus uitdagingen")
- Langzame studenten: stapje terug, vereenvoudigen, samen debuggen
**Student-taken:**
- Volg de comments in code
- Maak één kamer tegelijk af
- Gebruik Cursor: hover, autocomplete, quick fixes
- Vraag docent of klasgenoten als je vast zit (niet opgeven!)
**Mogelijke blokkades & oplossingen:**
| Probleem | Oorzaak | Oplossing |
|----------|---------|-----------|
| "Cursor geeft geen errors" | TypeScript niet correct geïnstalleerd | `npm install -D typescript` opnieuw |
| "Ik snap de hints niet" | Comment is te cryptisch | Docent vertaalt de hint in eigen woorden |
| "Ik kom niet verder" | Conceptueel niet begrepen | Teruggaan naar een eerder concept (Blok 3/4) |
| "Ik ben klaar" | Student is snel | Bonus challenges geven (zie onder) |
**Bonus uitdagingen** (voor snelle studenten):
1. **Generics:**
- Schrijf een `Container<T>` interface
- Gebruik het met verschillende types
2. **Advanced unions:**
- Maak een discriminated union: `type Result = { status: "success", data: string } | { status: "error", message: string }`
- Schrijf een functie die dit handlert
3. **Recursive types:**
- Definieer een boomstructuur type
- Maak een (eenvoudige) boomconstructor
4. **Type narrowing:**
- Schrijf functie die `string | number` handlert
- Gebruik `typeof` checks
**Spreektijd:** Afhankelijk van vragen (~20 min rond voor hulp) | **Student work:** ~55 min
**Materiaal:**
- TypeScript Escaperoom project (voorbereid)
- Hint card voor docent
- Bonus challenges (optioneel handout)
---
### Blok 8: Afsluiting (15 min | 11:45-12:00)
**Doel:** Reflectie, evaluatie, voorbereiding volgende les
**Activiteiten:**
1. **Escape codes vergelijken (~3 min):**
- Wie heeft de code afgerond? Welk nummer?
- Toon 2-3 juiste oplossingen op het scherm
- Complimenteer creativiteit / alternatieve approaches
2. **Samenvatting lesinhoud (~5 min):**
- Recap: "Wat hebben we vandaag geleerd?"
- Studenten noemen 3 dingen (whiteboard of verbal)
- Benadrukt: TypeScript = Cursors taal, nodig voor React/Next.js
3. **Huiswerk uitleggen (~4 min):**
- **Huiswerk Les 4:**
- Afmaken TypeScript Escaperoom (kamer 5 als niet afgerond)
- Lezen: [TypeScript Handbook] Sectie "Everyday Types" + "Narrowing"
- Voorbereidingsvraag: "Hoe zou je een type schrijven voor een functie die ALLES als input kan nemen?"
- Inleveren: screenshot escape code + reflectie (100 woorden): "Wat vond je van TypeScript? Welk concept was moeilijk?"
4. **Preview Les 5 (~3 min):**
- "Volgende les: TypeScript in React"
- Teasers: "Props typen", "State management", "Custom hooks"
- "Alles wat je vandaag hebt geleerd, gebruiken we volgende week in echte React-componenten"
**Spreektijd:** ~15 min | **Presentatie:** ~12 min
**Slides/Materiaal:**
- Samenvatting slide
- Huiswerk slide (duidelijk, ook digitaal beschikbaar)
- Les 5 teasers
---
## Materialen & Resources
### Bestanden in `/Les04-TypeScript-Fundamentals/`
```
Les04-TypeScript-Fundamentals/
├── Les04-Lesplan.md (dit bestand)
├── Les04-Slides.pptx
│ ├── Titelbanner
│ ├── JavaScript vs TypeScript
│ ├── Type overzicht
│ ├── Interface voorbeelden
│ ├── Function signatures
│ └── Samenvatting
├── Les04-Handout.pdf
│ ├── Type cheatsheet
│ ├── Common errors
│ └── Quick reference
├── Escaperoom-Project/
│ ├── README.md (setup instructies)
│ ├── package.json
│ ├── tsconfig.json
│ ├── src/
│ │ ├── kamer-1.ts (string, number, boolean)
│ │ ├── kamer-2.ts (arrays)
│ │ ├── kamer-3.ts (interfaces)
│ │ ├── kamer-4.ts (union types)
│ │ └── kamer-5.ts (functions)
│ ├── solutions/
│ │ ├── kamer-1.solution.ts
│ │ ├── kamer-2.solution.ts
│ │ ├── kamer-3.solution.ts
│ │ ├── kamer-4.solution.ts
│ │ └── kamer-5.solution.ts
│ └── escape-codes.txt
├── Les04-QuickStart.md (koppelingen naar externe resources)
├── Les04-References.md
│ ├── TypeScript Handbook links
│ ├── Video tutorials
│ └── Community resources
└── Les04-Homework.md
├── Leeswerk
├── Codingtaken
└── Reflectievragen
```
### Externe Resources
**Officieel:**
- [TypeScript Handbook - Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html)
- [TypeScript Handbook - Type Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html)
**Interactief:**
- TypeScript Playground: https://www.typescriptlang.org/play
- Oefeningen: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html
**Community:**
- Stack Overflow tag `typescript`
- Reddit: r/typescript
- Discord TypeScript community
---
## Voorbereiding Docent
### Checklist (1 week voor les)
- [ ] **Inhoud:** Alle slides af? Voorbeelden getest?
- [ ] **Demo:** Live coding-voorbeelden runnen in Cursor
- [ ] **Project:** Escaperoom project klaar? Alle kamers werkend?
- [ ] **Solutions:** Solutions files af (voor docent-reference)
- [ ] **Handout:** PDF klaar en gedownload op alle student-devices
- [ ] **Technisch:**
- [ ] TypeScript geïnstalleerd op eigen machine
- [ ] Cursor up-to-date
- [ ] Node.js versie recente (14+)
- [ ] **Communicatie:** Huiswerk vorige week teruggebeven?
### Checklist (1 dag voor les)
- [ ] **Slides:** Compleet doorgelopen, timing gecheck
- [ ] **Demo's:** Alle live coding-scripts getest
- [ ] **Project:**
- [ ] Project kloned/gedownload op eigen machine
- [ ] `npm install` succesvol
- [ ] Alle kamers kunnen draaien
- [ ] Escape codes gecontroleerd
- [ ] **Ruimte:**
- [ ] Projector werkt
- [ ] Netwerk stabiel
- [ ] Studentenlaptops hebben Cursor/IDE
- [ ] **Bonus:** Bonus challenges voorbereid (notities docent)
### Checklist (5 min voor les)
- [ ] Slides geopend
- [ ] Cursor open met voorbeeld-project
- [ ] Chat/Discord open (voor vragen)
- [ ] Timer gereed voor Blok 7 checkpoints
- [ ] Koffie klaar 😊
### Docent-notes & Timing
| Blok | Timing | Spreektijd | Notes |
|------|--------|-----------|-------|
| 1 | 10 min | 5 min | Energizer! Studenten voelen zich verwelkomd |
| 2 | 15 min | 12 min | **Live demo is cruciaal** studenten moeten begrijpen WAAROM |
| 3 | 15 min | 11 min | Type inference is abstract veel voorbeelden! |
| 4 | 15 min | 11 min | Interfaces/types zijn powerful dit is A-ha moment |
| 5 | 10 min | 8 min | Errors lezen is vaardigheid docent modeleert dit |
| 6 | 5 min | 5 min | Korte instructies, snel starten |
| **Pauze** | **15 min** | — | **Docent checkt techniek** |
| 7 | 75 min | 20 min | **Geduld!** Niet alle studenten gaan gelijkelijk |
| 8 | 15 min | 15 min | Celebrate wins! Huiswerk duidelijk maken |
**Timing-tips:**
- Blok 2 loopt soms uit → voorkomen met gerepeteerde demo
- Blok 3-4 zijn dicht → kunnen samengetrokken naar 25 min als nodig
- Blok 7 is flexibel → als studenten sneller gaan, langer doorgaan
- Blok 8 altijd uitvoeren (motivatie!)
---
## Veelvoorkomende Problemen & Oplossingen
| Probleem | Oorzaak | Symptoom | Oplossing |
|----------|---------|----------|-----------|
| **TypeScript errors zichtbaar** | Configuratie fout | Cursor toont geen rode underlines | `npm install -D typescript` + Cursor reload |
| **"Type 'any' is not assignable"** | Student begrijpt union types niet | Code werkt niet | Terug naar Blok 4, voorbeeld doen |
| **Interface vs Type verwarring** | Conceptueel niet verschil begrepen | Student wil type gebruiken voor objects | Venn diagram tonen, herhaald zeggen: "Interface = objects, Type = unions" |
| **"Ik snap type inference niet"** | Abstract concept | Student schrijft overal types | Laten zien dat Cursor het weet (hover) types zijn optioneel |
| **Functions niet getyped** | Syntax vergeten | Parameters hebben geen types | Toon `: type` syntax, laat repeteren |
| **Escaperoom kamer 3 (interfaces)** | Huiswerk niet gedaan | Student weet niet hoe interfaces werken | Docent doet voorbeeld samen, step-by-step |
| **Escaperoom kamer 5 (functions)** | Callback functions verwarrend | Student weet niet hoe functies als type te schrijven | Toon `(arg: Type) => ReturnType` syntax, veel oefenen |
| **Student verder willen** | Te makkelijk | Verliest interesse | Bonus challenges geven (zie Blok 7) |
| **Student achterblijven** | Te moeilijk | Frustratie, geeft op | Pair programming: docent/klasgenoot helpt |
| **Netwerk/technisch probleem** | WiFi down, npm install hangt | Nothing works | Fallback: offline Cursor examples, of pair programming |
---
## Leerresultaten & Evaluatie
### Hoe weet je dat studenten het snappen?
**Groen (begrepen):**
- ✅ Kan interface schrijven met optionele properties
- ✅ Ziet TypeScript error en weet wat het betekent
- ✅ Kan union type gebruiken in functie parameter
- ✅ Snapt verschil tussen type inference en expliciete types
**Oranje (deels):**
- ⚠️ Interfaces kan, union types nog niet
- ⚠️ Begrijpt errors, weet niet hoe op te lossen
- ⚠️ Haalt kamer 3-4 niet (maar 1-2 wel)
**Rood (niet begrepen):**
- ❌ Alles voelt "magie", begrijpt voordeel TS niet
- ❌ Hangt vast bij eerste kamers
- ❌ Huiswerk Les 3 niet gedaan (prerequisite gemist)
### Huiswerk Evaluatie
**Inleveringseisen:**
1. Screenshot van escape code (bewijs afronding)
2. Reflectie (100 woorden): "Wat vond je van TypeScript? Welk concept was moeilijk?"
**Rubric:**
- 5: Alle kamers af + thoughtful reflectie
- 4: Kamers 1-4 af + redelijke reflectie
- 3: Kamers 1-3 af of onvolledig werk
- 2: Kamers 1-2 af, reflectie te kort
- 1: Niet ingeleverd of onvoldoende
---
## Volgende Stap: Les 5 Preview
**Les 5: TypeScript for React/Next.js**
In Les 5 gebruiken studenten TypeScript in echte React-componenten:
- Props typen met interfaces
- State types
- Event handlers typen
- Custom hooks typen
- Nextjs pagina's en API routes
**Huiswerk Les 4 voorbereidt op Les 5:**
- Kunnen lezen wat types betekenen → begrijpen React props
- Union types kennen → discriminated unions in Redux/Zustand
- Optional properties kennen → optional React props
**Advies docent:**
- Veel les 5 oefenen met props-typen (meest praktisch)
- React errors (TypeScript gerelateerd) is groot probleem
- Early preparation (zeker van React basis vooraf)
---
## Notities Docent (vrijruimte)
```
Notities voor eigen voorbereiding:
- Welke voorbeelden zelf toevoegen?
- Welke students extra aandacht nodig?
- Timing aanpassingen van vorig jaar?
- Lokale resources (Slack, Discord)?
- Volgende keer: ...
[Ruimte voor docent-notities]
```
---
## Bijlage: Keyboard Shortcuts & Tools
### Cursor Shortcuts (essentieel)
| Actie | Shortcut |
|-------|----------|
| Command Palette | `Ctrl+Shift+P` (Win/Linux) / `Cmd+Shift+P` (Mac) |
| Go to Definition | `F12` of `Ctrl+Click` |
| Rename Symbol | `F2` |
| Quick Fix | `Ctrl+.` |
| Format Document | `Shift+Alt+F` |
| Terminal | `Ctrl+`` |
### TypeScript Commands
```bash
# Project setup
npm init -y
npm install -D typescript
# TypeScript compiler
npx tsc --version
npx tsc --init # tsconfig.json genereren
npx tsc # compileren
npx tsc --watch # auto-compileren
```
### Handige Extensions (voor Cursor)
- TypeScript Vue Plugin
- Error Lens (errors inline tonen)
- Peacock (editor herkennen per workspace)
---
## Reflectie & Verbeteringen
### Van vorig jaar (indien van toepassing)
- [ ] Wat werkte goed?
- [ ] Wat moet beter?
- [ ] Welke voorbeelden updaten?
- [ ] Timing aanpassingen?
### Voor volgende jaar
- Meer live debugging van TypeScript errors?
- Minder of meer Blok 7 challenges?
- Escaperoom moeilijkheidsgraad OK?
- Student feedback ingebouwd?
---
**Laatst bijgewerkt:** 27 februari 2026
**Versie:** 1.0
**Docent:**
**Cursuscoördinatoren:**
*Veel succes met Les 4! TypeScript is een game-changer voor student-developers. Zorg dat ze voelen dat ze iets magisch leren.*

View File

@@ -0,0 +1,772 @@
# Les 4: TypeScript Fundamentals - Slide Overzicht
## Docentenhandleiding voor Tim
Welkom bij Les 4! Vandaag gaan we TypeScript introduceren - het moment waarop JavaScript echt volwassen wordt. We starten met het probleem dat TypeScript oplost, en daarna duiken we direct in de praktijk.
**Timing**: Ongeveer 90-120 minuten met hands-on escaperoom aan het eind.
---
## Slide 1: Titel - "Les 4: TypeScript Fundamentals"
### Op de Slide
- Grote titel: **"Les 4: TypeScript Fundamentals"**
- Subtitel: "Maak JavaScript sterker met types"
- Kleine visual: TypeScript logo (blauw)
- Datum: Les 4 van 18
### Docentnotities
Begin energiek! "Jongens, we gaan vandaag het allerbelangrijkste ding leren die elke moderne JavaScript developer moet weten. Jullie hebben gisteren misschien al wat fouten gehad die lastig waren om te vinden - TypeScript lost dat op. We gaan vandaag ontdekken waarom bedrijven als Netflix, Airbnb, en Google TypeScript gebruiken.
Wie van jullie heeft al gehoord van TypeScript? Oké, vandaag gaat dat veranderen!"
---
## Slide 2: Planning Vandaag
### Op de Slide
- **Blok 1** (30 min): Het Probleem & De Oplossing
- Waarom TypeScript nodig is
- Hoe het werkt in het ecosysteem
- **Blok 2** (40 min): Type Basics
- Basic types (string, number, boolean)
- Arrays en Interfaces
- Union types en Type Aliases
- **Blok 3** (30 min): Hands-On Escaperoom
- 8 kamers om door heen te gaan
- Type fouten opsporen en fixen
### Docentnotities
"Dit is onze agenda voor vandaag. We beginnen met de context - WAAROM gebruiken we TypeScript? Dat is superbelangrijk. Daarna leren we de basisvaardigheden om types te schrijven. En het mooiste: jullie gaan zelf aan de slag met een interactieve escaperoom waar je type fouten moet fixen.
Iedereen klaar? Laten we beginnen!"
---
## Slide 3: Terugblik Les 3 - Cursor & Debugging
### Op de Slide
- Screenshot van Cursor IDE
- Kleine code snippet met breakpoint
- Vraagsteken: "Hoeveel bugs hebben we voorkomen kunnen worden?"
### Docentnotities
"Gisteren hebben we geleerd hoe we bugs opsporen met de debugger in Cursor. We zetten breakpoints, we keken naar variabelen, we snapten wat er misgaat. Super belangrijk, maar... dit was reactive debugging. We zoeken NADAT er al iets fout is gegaan.
TypeScript is iets speciaals: het is PREactive debugging. We stoppen fouten VOORDAT ze ontstaan - nog voor je code runt.
En: hoe ging die debug challenge? Wie heeft het kunnen oplossen? Goed gedaan! Dat was lastig. Maar met TypeScript wordt het veel makkelijker."
---
## Slide 4: Het Probleem met JavaScript
### Op de Slide
```javascript
function calculateTotal(price, quantity) {
return price * quantity;
}
const total = calculateTotal("25.99", 3);
console.log(total); // "25.99" + "25.99" + "25.99" = "25.9925.9925.99"
```
- Boven de code: rood kruisje "❌ Geaccepteerd door JavaScript"
- Onder: "Bij runtime descobt je een rare bug!"
### Docentnotities
"Oké, hier is het probleem. Ik bel `calculateTotal` aan met een string in plaats van een getal. JavaScript zegt... niks. Geen fout. Maar als je het draait, is het totaal compleet fout!
Waarom? Omdat JavaScript dynamisch getypeerd is. Het zegt: 'Jij bent verantwoordelijk voor types, niet ik. Ik ga gewoon doen wat je zegt.'
En kijk: JavaScript voert dit uit en geeft je het verkeerde antwoord. Je debuggt je code, je kijkt naar je network requests, misschien denk je dat je backend kapot is... maar nee, de bug zit hier.
Dit soort fouten kunnen weken werk kosten. Elke developer in deze kamer heeft dit al eens meegemaakt."
---
## Slide 5: De Oplossing: TypeScript
### Op de Slide
```typescript
function calculateTotal(price: number, quantity: number): number {
return price * quantity;
}
const total = calculateTotal("25.99", 3);
// ^^^^^^^^
// ❌ ERROR: Argument of type 'string' is not assignable to parameter of type 'number'
```
- Boven: "✅ TypeScript vangt dit bij compile time!"
- Verschil met vorige slide: rode squiggle onder de string
### Docentnotities
"Nu met TypeScript. We zeggen: 'Hé, `price` moet een number zijn. `quantity` moet een number zijn. En deze functie geeft een number terug.'
Wat gebeurt er? TypeScript ziet deze aanroep en zegt: 'Wacht even... je geeft me een string en ik verwacht een number. Nope!'
Het mooie: dit gebeurt VOORDAT je code draait. Je ziet het rode squiggle in Cursor. Je fix het meteen. Geen runtime bugs, geen mysterieuze errors in je logs.
Dit is waarom TypeScript zo powerful is. Het voelt als een vriend die voortdurend over je schouder meekijkt en zegt: 'Ehm, dit gaat fout...'"
---
## Slide 6: Waarom TypeScript? - 4 Voordelen
### Op de Slide
Vier vakken met iconen en tekst:
1. **🐛 Fouten Voorkomen**
- Vind fouten VOOR je app draait
- Spaar debugging tijd
2. **📝 Betere Documentatie**
- Types zijn documentatie
- "Wat verwacht deze functie?"
3. **🚀 Autocomplete & IntelliSense**
- Cursor weet wat je wilt typen
- 10x sneller coderen
4. **🛡️ Refactoring Veilig**
- Verander code met vertrouwen
- TypeScript ziet als je iets breekt
### Docentnotities
"Waarom gebruiken we dit eigenlijk? Laten we de vier grote wins opsommen:
**Eerst**: Fouten voorkomen. Dit hebben we net gezien. Je code runt niet meer met domme type fouten.
**Tweede**: Betere documentatie. Types zijn eigenlijk documentatie. Kijk naar een functie - je ziet exact wat het verwacht en geeft terug. Geen giswerk meer.
**Derde**: Autocomplete. Dit is echt magisch. Jullie gaan dit ervaren vandaag. Je typt `person.` en Cursor weet EXACT welke properties beschikbaar zijn. Veel sneller coderen.
**Vierde**: Veilig refactoring. Stel je hebt 50 plaatsen in je code die een bepaalde functie aanroepen. Je verandert die functie. TypeScript zegt meteen: 'Hé, je hebt nu 37 plaatsen die breuk zijn'. Je fix ze allemaal op een rij. Zonder TypeScript? Goedemiddag, productie bugs!
Dit is waarom Netflix, Google, Microsoft - allemaal gebruiken TypeScript."
---
## Slide 7: TypeScript in het Ecosysteem
### Op de Slide
- Grote TypeScript logo in het midden
- Pijlen naar omringende technologieën met logos:
- Next.js (TypeScript default)
- React (kan TypeScript)
- Vue (kan TypeScript)
- Svelte (TypeScript support)
- Node.js (TypeScript via ts-node)
- Deno (TypeScript first)
Tekst onderin: "TypeScript is de standaard, niet de uitzondering"
### Docentnotities
"Hier is iets belanrijks: TypeScript is niet meer iets speciaals. Het is de industrie standaard.
Next.js? Maken jullie volgende les. TypeScript is er standaard in gebakken. React? Alle Enterprise React projecten gebruiken TypeScript. Vue? Svelte? Allemaal excellent support.
Zelfs Node.js heeft TypeScript support gebuild. Deno - die is van de maker van Node - is TypeScript first. Geen JavaScript, direct TypeScript.
Dit zegt: als je modern wilt programmeren, moet je TypeScript kennen. Het is niet optional meer, het is expected."
---
## Slide 8: Basic Types - De Fundamenten
### Op de Slide
```typescript
// String
const name: string = "Alice";
// Number
const age: number = 25;
// Boolean
const isActive: boolean = true;
// any (vermijden!)
let anything: any = "whatever";
anything = 123; // Dit gaat altijd door
```
Tekstbox: "Vier basistypen. `any` is je vijand!"
### Docentnotities
"Oké, de absolute basisvaardigheden. TypeScript heeft standaard types die je krijgt:
String - tekst. Easy. Number - getallen, zowel integers als floats. Boolean - true of false.
Dan is er `any`. Dit is het laziness keyword. `any` zegt: 'Ik weet niet wat dit is, doe maar wat je wilt.' Dat is het hele punt van TypeScript verpest. We gaan `any` zo veel mogelijk vermijden. Als ik `any` zie in jullie code... ja, we hebben een probleem!
Let op: je HOEFT niet altijd types te schrijven. TypeScript kan ze raden. Maar soms moet je ze expliciet zeggen. Dat zien we straks."
---
## Slide 9: Arrays - Collecties Typen
### Op de Slide
```typescript
// Array notation 1: type[]
const numbers: number[] = [1, 2, 3];
// Array notation 2: Array<T>
const names: Array<string> = ["Alice", "Bob"];
// Gemengd - FOUT!
const mixed: number[] = [1, "twee", 3];
// ^^^^^^ ERROR!
// Arrays van objecten
const users: User[] = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
```
Kleurtje: beide notaties zijn equivalent, maar `type[]` is populairder
### Docentnotities
"Arrays zijn collections. TypeScript wil weten WELK TYPE in de array zit.
Je kan zeggen: 'Dit is een array van numbers' met `number[]`. Of je kan zeggen `Array<string>` - beide doen hetzelfde. De eerste notatie is sneller om te typen.
Het mooie: als je een string in een number array probeert te stoppen, TypeScript zegt nee. Je ziet meteen het rood.
En ja, je kan arrays van objecten hebben. We zien straks interfaces, dan wordt dit echt nuttig."
---
## Slide 10: Type Inference - TypeScript Raadt
### Op de Slide
```typescript
// TypeScript RAADT het type
const age = 25;
// age is nu: number
const userName = "Alice";
// userName is nu: string
// Je hoeft niet altijd expliciet te zijn
function greet(name) {
// ^^^^ Hier WIL je wel annotatie
return `Hello, ${name}!`;
}
// BETER:
function greet(name: string): string {
return `Hello, ${name}!`;
}
```
Tekstbox: "TypeScript raadt types. Maar functies? Die moeten explicit!"
### Docentnotities
"Dit is cool en belangrijk: TypeScript is slim. Kijk naar `age = 25`. TypeScript ziet: 'Dit is een 25, dus number'. Ze hoeft niks te zeggen.
Hetzelfde met strings. Dit is type inference - TypeScript RAADT wat je bedoelt.
MAAR - en dit is groot - bij functies moet je explicit zijn. Waarom? Omdat TypeScript je functie niet kan raden. Je moet zeggen: 'Dit parameter is een string, en ik geef een string terug.'
Dit is een best practice: bij variabelen kan TypeScript raden, bij functies moet je explicit zijn. Dat staat duidelijk in je code: dit is het contract van deze functie."
---
## Slide 11: Interfaces - Object Vormen Definiëren
### Op de Slide
```typescript
// Een interface is een beschrijving van een object
interface User {
id: number;
name: string;
email: string;
age?: number; // Optional
}
// Nu kan je dit type gebruiken
const user: User = {
id: 1,
name: "Alice",
email: "alice@example.com"
};
// Vergeten iets essentiëls?
const incomplete: User = {
id: 2,
name: "Bob"
// ❌ ERROR: Property 'email' is missing
};
```
### Docentnotities
"Dit is het hart van TypeScript: interfaces. Een interface zegt: 'Een User ziet er zo uit'.
Kijk naar deze interface. Een User MOET een `id` hebben (number), een `name` (string), en `email` (string). Optioneel is `age`.
Nu, als je probeerde een User te maken zonder `email`? TypeScript zegt nee. Red squiggle. Je MOET dit toevoegen.
Dit is super krachtig voor data structuren. Je weet EXACT welke shape je objecten moeten hebben. Je collega's weten het. TypeScript weet het. Geen gissing meer."
---
## Slide 12: Optional Properties - De ? Syntax
### Op de Slide
```typescript
interface Product {
name: string; // Verplicht
price: number; // Verplicht
description?: string; // Optional
discount?: number; // Optional
}
// Dit gaat goed:
const product: Product = {
name: "Laptop",
price: 999
};
// Dit ook:
const productWithDesc: Product = {
name: "Mouse",
price: 25,
description: "Wireless mouse"
};
// Dit gaat FOUT:
const noName: Product = {
price: 100
// ❌ ERROR: Property 'name' is missing
};
```
Boven aan: "Het vraagteken maakt properties optioneel!"
### Docentnotities
"Merk je dat vraagteken op? `description?: string`. Dat zegt: 'Dit property mag er zijn, maar het hoeft niet.'
Zo maak je flexible interfaces. Sommige dingen zijn altijd nodig (naam, prijs), andere zijn nice-to-have (beschrijving, korting).
Dit is realistisch. Je kan niet altijd alles invullen. Dus zeg je tegen TypeScript: deze dingen zijn optioneel. Dit geeft je flexibiliteit zonder je type safety te verliezen."
---
## Slide 13: Type Aliases - De `type` Keyword
### Op de Slide
```typescript
// Type alias met union
type Status = "pending" | "approved" | "rejected";
// Type alias met object shape
type Address = {
street: string;
city: string;
zipCode: string;
};
// Je kan ervan uitbreiden
type Employee = {
id: number;
name: string;
address: Address; // Ander type gebruiken
status: Status;
};
// In een functie
function updateEmployeeStatus(
employeeId: number,
newStatus: Status
): void {
// ...
}
```
### Docentnotities
"Nu `type` - dit is eigenlijk meer flexibel dan interface. Een type kan alles zijn.
Met type can je union types maken - meer daarover straks. Je kan object shapes definieren, net als interfaces. Maar je kan ook getallen, strings, unions combineren.
De rule: interfaces voor objecten en klassen, types voor alles. Maar in de praktijk? Veel developers gebruiken type overal. Het werkt beide kanten uit.
Key point: dit zijn twee manieren om dezelfde dingen te doen. Interface is meer traditioneel, type is meer modern. Wij gaan voornamelijk interfaces gebruiken, maar kennen type."
---
## Slide 14: Union Types - Multiple Mogelijkheden
### Op de Slide
```typescript
// Een waarde kan EEN van deze types zijn
type Status = "pending" | "approved" | "rejected";
function handleStatus(status: Status) {
if (status === "pending") {
console.log("Wachten op review...");
} else if (status === "approved") {
console.log("Goedgekeurd!");
} else if (status === "rejected") {
console.log("Afgewezen, je kan opnieuw proberen.");
}
}
// Dit gaat:
handleStatus("approved");
// Dit gaat NIET:
handleStatus("cancelled");
// ❌ ERROR: Argument of type '"cancelled"' is not assignable
// Union van types
type Result = string | number;
const value: Result = 42; // OK
const text: Result = "hello"; // OK
const arr: Result = []; // FOUT!
```
### Docentnotities
"Union types zijn heel nuttig. Ze zeggen: 'Dit kan dit type zijn, óf dit type.'
Kijk naar Status. Een status kan `pending`, `approved`, of `rejected` zijn. Niet meer, niet minder. Als je `cancelled` probeert? Nee, TypeScript blokkeert het.
Dit is super veilig. Je ziet een status, je weet precies welke mogelijkheden er zijn. Geen gegooi met magic strings.
Je kan ook types unionen: `string | number` betekent 'dit kan een string zijn OF een number'. Handig soms, maar voorzichtig - het maakt je code komplexer."
---
## Slide 15: Interface vs Type - Wanneer Welke?
### Op de Slide
Twee kolommen:
**Interface**
- Voor object shapes
- Kan geextend worden (`extends`)
- Traditioneel OOP approach
- Foutmeldingen: duidelijker
**Type**
- Voor alles (objects, unions, primitives)
- Meer flexibel
- Modern, functioneel approach
- Kan unioned worden (`&`, `|`)
Onderin: "Regel: Gebruik interface tenzij je een union of conditional nodig hebt. Dan type."
### Docentnotities
"Dus wat kies je? Interface of type?
Makkele regel: standaard interface. Interfaces zijn voor objecten. Ze zijn duidelijk, ze zijn traditioneel, ze extensible. Als je een object shape gaat beschrijven, interface.
Type kies je als je iets ingewikkelds nodig hebt. Union types, conditionals, primitieve types. Type is flexibeler.
In jullie code gaan jullie vooral interfaces zien. Dat is goed. Interfaces zijn simpel en duidelijk. Types zijn voor wanneer je echt nodig hebt."
---
## Slide 16: Functies Typen - Parameters & Return
### Op de Slide
```typescript
// Simpele functie
function add(a: number, b: number): number {
return a + b;
}
// Met optionele parameter
function greet(name: string, greeting?: string): string {
const msg = greeting || "Hello";
return `${msg}, ${name}!`;
}
// Arrow function
const multiply = (x: number, y: number): number => x * y;
// Met interface parameters
interface User {
id: number;
name: string;
}
function displayUser(user: User): void {
console.log(`${user.name} (#${user.id})`);
// void = geen return value
}
// Complex: return een object
function authenticate(username: string, password: string): { success: boolean; token?: string } {
// ... logica
}
```
### Docentnotities
"Functies typen is makkelijk: zeg wat elk parameter is, en wat je teruggeeft.
`add` neemt twee numbers, geeft een number terug. Simpel.
`greet` heeft een optionele parameter - dat `greeting?`. Die zeggen: 'Dit kan weggelaten worden'.
`multiply` - arrow function. Zelfde regel: parameters en return type.
`displayUser` geeft niets terug - `void`. Dat is belangrijk, `void` zegt: 'Deze functie returnt niks, het doet alleen iets.'
En die laatste - je kan complexe return types hebben. Dit geeft een object terug met `success` en optionele `token`. Handig voor API responses.
Dit is essentieel. Iedere functie die je schrijft moet getypeerd zijn. Geen uitzonderingen."
---
## Slide 17: Veelvoorkomende Errors - Top 3
### Op de Slide
```typescript
// ERROR 1: Type Mismatch
const age: number = "25";
// ❌ Type 'string' is not assignable to type 'number'
// FIX: const age: number = 25;
// ERROR 2: Missing Property
interface User {
id: number;
name: string;
}
const user: User = { id: 1 };
// ❌ Property 'name' is missing in type '{}'
// but required in type 'User'
// FIX: const user: User = { id: 1, name: "Alice" };
// ERROR 3: Cannot read property of undefined
const person = { name: "Alice" };
console.log(person.age.toUpperCase());
// ❌ Object is possibly 'undefined'
// FIX: console.log(person.age?.toUpperCase());
// (optional chaining)
```
### Docentnotities
"Oké, je gaat deze drie errors constant zien. Leer ze kennen:
**Error 1**: Type mismatch. Je probeert een string aan een number toe te wijzen. TypeScript zegt 'nee'. Fix: zorg dat je types overeenstemmen.
**Error 2**: Missing property. Je maakt een object van type User, maar je vergeet de naam. TypeScript ziet dat. Fix: vul alles in dat nodig is.
**Error 3**: Dit is subtiel. `person.age` bestaat misschien niet, dus het is `undefined`. Dan probeer je `.toUpperCase()` op undefined te roepen - crash! Fix: gebruik optional chaining (`?.`). Dat zeggen we volgende les meer over.
Zie je deze errors? Geen paniek. Ze helpen je eigenlijk. Ze voorkomen echte bugs."
---
## Slide 18: Cursor + TypeScript - Superkrachten
### Op de Slide
- Screenshot van Cursor met autocomplete dropdown
- Pijlen naar drie features:
1. **IntelliSense Autocomplete**
- Type `user.` → alle properties
- Sneller coderen, 0 fouten
2. **Error Underlines**
- Rood squiggle meteen
- Fix knop voordat je runt
3. **Go to Definition**
- Cmd+Click op type
- Zie exact wat het is
### Docentnotities
"Dit is waarom Cursor zo goed is. Cursor en TypeScript samen zijn echt magisch.
Stel: je hebt een User object. Je typt `user.` en Cursor weet EXACT welke properties die User heeft. Je hoeft niet te gokken. Je ziet de lijst. Autocomplete. Sneller coderen.
Dan: je maakt een fout. Meteen rode squiggle. Je hoeft niet in tests of bij runtime te wachten. Je ziet het direct. En Cursor kan je sometimes helpen met een fix knop.
En: als je een type wil zien, click je erop met Cmd. Cursor springt je naar die definition. Zo leer je ook dingen - je ziet hoe andere types gebouwd zijn.
Dit is waarom professionele developers TypeScript gebruiken. Cursor en TypeScript samen zijn een superkracht."
---
## Slide 19: Hands-On - TypeScript Escaperoom Introductie
### Op de Slide
- Titel: **"TypeScript Escaperoom: 8 Kamers"**
- Grafisch: 8 deuren/kamers visueel weergegeven
- Kleuren: Groen, Geel, Oranje, Rood (difficulty)
**Kamers:**
1. 🟢 Basic Types (Easy)
2. 🟢 Arrays & Interfaces (Easy)
3. 🟡 Optional Properties (Medium)
4. 🟡 Union Types (Medium)
5. 🟠 Function Types (Medium-Hard)
6. 🟠 Complex Interfaces (Hard)
7. 🔴 Mixed Errors (Very Hard)
8. 🔴 Real-World Scenario (Very Hard)
### Docentnotities
"Oké, dit is het leukste deel. Jullie gaan naar een TypeScript escaperoom - acht kamers met type fouten die jullie moeten fixen.
Kamer 1 t/m 2 zijn warm-ups. Basic types, arrays. Makkelijk.
Kamer 3 t/m 5 zijn medium. Je gaat optional properties zien, unions, functies typen. Dit is waar het echt begint.
Kamer 6 t/m 8? Dit is hard. Real-world scenarios. Echt code die je ziet in bedrijven.
Je gaat dit samen doen in teams van twee. Ik loop rond, ik help als je stuck bent. Maar eerst probeer je het zelf! Dat is hoe je leert.
Klaar voor de escaperoom?"
---
## Slide 20: Escaperoom Rules & Structuur
### Op de Slide
```
Hoe het werkt:
1. Open de Escaperoom Challenges
2. Lees de beschrijving
3. FIX de TypeScript errors
4. TypeScript moet geen errors meer geven
5. Test in browser als nodig
6. Ga naar volgende kamer!
RULES:
✅ Je mag Cursor foutmeldingen gebruiken
✅ Je mag vorige slides terugbekijken
✅ Je mag je teamgenoot vragen
✅ Je mag mij vragen (als laatste resort!)
❌ Je mag niet 'any' gebruiken om fouten te vermijden
❌ Je mag niet kopieren van anderen
❌ Je mag niet opgeven! 😄
TIMING:
- 40 minuten om zoveel kamers als mogelijk uit te voeren
- Minstens kamer 1-5 halen is succes
- Kamer 6-8 zijn bonus
```
### Docentnotities
"Hier zijn de regels. Dit is serieus, maar ook echt leuk. Jullie gaan bugs fixen en TypeScript mastery opbouwen.
Wat mogen jullie NIET doen? Die fouten niet gewoon oversla met `any`. `any` is cheating - het voorbijgaat heel TypeScript. Dat gaat niet gebeuren.
Wat mogen jullie WEL doen? Cursor gebruiken! Terug naar slides kijken! Me vragen!
Ik ga de escaperoom opstarten. Jullie werken in teams. Ik loop rond, ik help. Maar probeer eerst zelf!
Laten we gaan. Wie is nerveus? Goed! Dat betekent dat je gaat leren. Zet op!"
---
## Slide 21: Samenvatting - Key Takeaways
### Op de Slide
Vijf grote punten:
1. **TypeScript vangt fouten VOORDAT je code draait**
- Geen runtime surprises meer
2. **Types zijn als documentatie**
- Iedereen weet wat een functie verwacht
3. **Vier basisconcepten**
- Basic Types, Arrays, Interfaces, Union Types
4. **Cursor & TypeScript = Superkrachten**
- Autocomplete, Error detection, Safe refactoring
5. **Oefening = Meesterschap**
- Je bent nooit klaar met leren, maar escaperoom is een goeie start
### Docentnotities
"Recap. Dit is wat je vandaag hebt geleerd:
TypeScript is preventief. Je ziet fouten voor ze zich voordoen. Dat sparen je uren debuggen.
Types zijn documentatie. Je code zegt wat het verwacht. Niemand hoeft vragen meer te stellen.
De basics: strings, numbers, booleans. Arrays van types. Interfaces voor object shapes. Unions voor multiple mogelijkheden. Dit zijn je fundamenten.
Cursor maakt TypeScript sterker. IntelliSense, error detection, safe refactoring. Deze drie dingen together zijn unstoppable.
En oefening. Je bent nooit klaar met TypeScript. Er is altijd meer om te leren. Maar vandaag hebben jullie een stevige basis gelegd."
---
## Slide 22: Huiswerk & Preview Les 5
### Op de Slide
**Huiswerk (les 4):**
- Finaliseer zoveel escaperoom kamers als je kan
- Verzend je TypeScript file naar me (geen `any`!)
- Lees het TypeScript Handbook intro (5 minuten)
**Preview les 5 - Next.js Basics:**
- Next.js setup
- File-based routing
- Eerste pagina's maken
- TypeScript in Next.js
- Deploy naar Vercel
Visual: Next.js logo met pijl naar "Les 5"
### Docentnotities
"Huiswerk: finaliseer die escaperoom. Verzend je file naar me. Ik wil geen `any` zien, anders stuur ik het terug!
En lees het TypeScript Handbook intro. Niet heel veel tijd, maar het helpt je context.
Volgende les? NEXT.JS. Dit is waar het echt spannend wordt. Jullie gaan echte web apps bouwen met React, TypeScript, en all the bells and whistles.
Next.js is het framework dat everyone uses. Vercel (de makers) gebruiken het. Jullie gaan het morgen gebruiken.
Dus zorg dat je huiswerk doet. Het volgende is big.
Goed werk vandaag! Ik ben trots op jullie. Tot volgende keer!"
---
## Aanvullende Notities voor Tim
### Timing-hints
- **Slide 1-7** (Context): ~15 minuten
- **Slide 8-18** (Learning): ~30-40 minuten (veel code voorbeelden, veel interactie verwacht)
- **Slide 19-20** (Escaperoom setup): ~5 minuten
- **Escaperoom praktijk**: ~40 minuten
- **Slide 21-22** (Afsluiting): ~5 minuten
### Interactie Suggesties
- **Na Slide 5**: "Wie ziet hoe dit echt helpt?" - laat ze reageren
- **Bij Slide 8-14**: Toon elke slide, code voorbeel, dan vraag "Vragen?"
- **Bij Slide 16**: Laat ze zelf een getypeerde functie schrijven in Cursor (live, samen)
- **Bij Escaperoom**: Loop rond, help gefocust (niet de hele antwoord geven)
### Mogelijke Vragen
- **"Waarom niet altijd `any` gebruiken?"** → Antwoord: Dan ben je terug naar JavaScript. Geen voordeel.
- **"Wat is het verschil tussen interface en type?"** → Antwoord: Interface = objects, type = alles. Maar veel developers gebruiken type overal.
- **"Hoe fix ik deze error?"** → Antwoord: Laat ze Cursor's error message lezen. Die zijn eigenlijk heel helpful.
### Code Examples Best Practices
Zorg dat je:
1. Copy-paste code in je Cursor project
2. Laat TypeScript errors verschijnen (rood squiggle)
3. Fix het LIVE, zodat ze zien hoe het werkt
4. Vraag: "Waarom was dit fout?"
### Escaperoom Technicals
- Je hebt een GitHub repo nodig met TypeScript challenges (8 files)
- Elke file has `// TODO: Fix the TypeScript errors`
- Students moeten `npm install` doen, dan `npx tsc` runnen
- Als TypeScript clean is (0 errors), is de kamer completed
Veel succes, Tim! Dit is een sterke les!

Binary file not shown.

View File

@@ -1,125 +1,114 @@
# Les 3: AI Ethics, Privacy & Security + WebStorm Integration
# Les 3: Cursor Setup & Basics
> 📋 **Lesmateriaal nog niet uitgewerkt**
> **Les gegeven op woensdag 26 februari 2026**
>
> De volgende bestanden worden gegenereerd wanneer deze les wordt uitgewerkt:
> - Les03-Slide-Overzicht.md
> - Les03-Lesplan.md
> - Les03-Bijlage-A-Lesopdracht.md
> - Les03-Bijlage-B-Huiswerkopdracht.md
> Lesmateriaal volledig uitgewerkt:
> - [Slide-Overzicht](../Les03-Cursor-Basics/Les03-Slide-Overzicht.md)
> - [Lesplan](../Les03-Cursor-Basics/Les03-Lesplan.md)
> - [Docenttekst](../Les03-Cursor-Basics/Les03-Docenttekst.md)
> - [Keynote Notes](../Les03-Cursor-Basics/Les03-Docenttekst-Notes.md)
> - [Lesopdracht](../Les03-Cursor-Basics/Les03-Bijlage-A-Lesopdracht.md)
> - [Huiswerkopdracht](../Les03-Cursor-Basics/Les03-Bijlage-B-Huiswerkopdracht.md)
> - [Hands-On Opdracht (PDF)](../Les03-Cursor-Basics/Les03-Hands-On-Opdracht.pdf)
> - [Huiswerkopdracht (PDF)](../Les03-Cursor-Basics/Les03-Huiswerkopdracht.pdf)
> - Debug Challenge zips: standaard (5 fouten), hard (12 fouten), super hard (18 fouten)
---
## Hoofdstuk
**Deel 1: AI Foundations** (Les 1-4)
## Context
Oorspronkelijk zou les 3 gaan over AI Ethics, Privacy & Security. Tim heeft besloten om in plaats daarvan een praktische les over Cursor te geven. Dit sluit beter aan bij wat studenten nodig hebben en was een goede keuze — studenten waren enthousiast.
## Beschrijving
Cruciale kennis over veilig en ethisch werken met AI, gecombineerd met professionele IDE workflow.
Praktische les over Cursor als primaire AI-powered editor. Studenten leren Cursor installeren, configureren en gebruiken om een compleet Next.js project op te zetten.
---
## Te Behandelen
### Groepsdiscussie (15 min)
Bespreek klassikaal de blog posts uit Les 2 - wat waren de ervaringen met AI-assisted coding? Welke limitations ontdekte je?
### Blok 1: Cursor Overzicht (15 min)
- Wat is Cursor? VS Code fork met AI
- Free vs Pro vs Student Plan (500 fast requests/maand)
- Request types: Tab Completion (gratis), Chat, Composer, Inline Edit (elk 1 request)
### Deel 1: Ethics, Privacy & Security (1 uur)
### Blok 2: Samen Doen — Setup Check (10 min)
- Terminal check: node -v, git --version, npm -v, npx -v
- Cursor Student Plan activeren via cursor.com/students
**Privacy Risico's - Wat NOOIT te delen:**
- API keys
- Client data
- Credentials
- Persoonlijke informatie
### Blok 3: Cursor Skills & Docs (10 min)
- Settings → Features → Docs: Next.js, React, Tailwind toevoegen
- @docs mentions in Chat voor framework-specifieke hulp
**Overige Onderwerpen:**
- Data ownership bij AI services
- Bias in AI models
- Security vulnerabilities (SQL injection, XSS, prompt injection)
- GDPR/AVG compliance basics
- Professional responsibility als developer
- Wanneer gebruik je AI wel/niet?
### Blok 4: Nieuw Project Aanmaken (15 min)
- git init → npx create-next-app@latest
- TypeScript, Tailwind, App Router, src/ directory
### Deel 2: WebStorm Integration (1 uur)
### Blok 5: .cursorrules Genereren (10 min)
- Via Cursor Chat (Ctrl+L / Cmd+L) — kost 1 request
- Project-specifieke regels voor Next.js, Tailwind, TypeScript
**WebStorm Setup:**
- WebStorm installatie (gratis via school licentie)
- OpenCode plugin voor WebStorm installeren en configureren
### Blok 6: Keyboard Shortcuts & Request Management (15 min)
- Tab = gratis autocomplete
- Ctrl+K / Cmd+K = Inline Edit (1 request)
- Ctrl+L / Cmd+L = Chat (1 request)
- Ctrl+I / Cmd+I = Composer (1 request)
- Slim combineren van taken in 1 prompt
**Voordelen IDE vs Standalone:**
- Project context
- Git integration
- Debugging
- Refactoring tools
### Pauze (15 min)
**Live Demo:**
- Zelfde taak in OpenCode standalone vs WebStorm
### Blok 7: Hands-On — Bouw Componenten (75 min)
- Taak 1: Hero Component via Composer
- Taak 2: Styling tweaken via Inline Edit
- Taak 3: Extra feature naar keuze (FeatureCards, ContactForm, of Footer)
- Git commit
- Verder bouwen voor wie klaar is
---
## Tools
- WebStorm (school licentie)
- OpenCode plugin
- Git
- Cursor (Student Plan — gratis Pro voor studenten)
- Git & GitHub
- Node.js + npx
- Next.js, TypeScript, Tailwind CSS
---
## Lesopdracht (2 uur)
## Lesopdracht (75 min — hands-on na pauze)
Beschikbaar als losse PDF: [Les03-Hands-On-Opdracht.pdf](../Les03-Cursor-Basics/Les03-Hands-On-Opdracht.pdf)
### Deel 1: Security Workshop (1 uur)
**Groepswerk (30 min):**
- Docent toont 3 AI-generated code snippets met security/privacy issues
- Studenten identificeren problemen in groepjes
**Individueel (30 min):**
- Laat AI code genereren voor een login form
- Review op security
- Fix problemen
- Maak persoonlijke "AI Safety Checklist" voor toekomstig gebruik
### Deel 2: WebStorm Setup (1 uur)
**Setup:**
- Installeer WebStorm met school licentie
- Installeer OpenCode plugin
- Configureer met je model
**Vergelijking:**
- Rebuild een component uit Les 2 in WebStorm
- Ervaar het verschil
**Documentatie:**
- Voordelen van IDE vs standalone
- Welke workflow prefereer je?
Stappen:
1. Nieuw project aanmaken (git init, npx create-next-app, npm run dev)
2. Cursor configureren (Skills/Docs, .cursorrules genereren)
3. Componenten bouwen (Hero via Composer, styling via Inline Edit, extra feature)
4. Git commit
---
## Huiswerk (2 uur)
## Huiswerk: Debug Challenge
**Bouw Secure Feature:**
Kies één van:
- Contact form met server-side validatie
- User authentication flow met JWT
Studenten krijgen een intentioneel kapot Next.js project en moeten het repareren met Cursor. Drie moeilijkheidsniveaus:
**Process:**
1. Laat AI initial code genereren
2. Review met je Safety Checklist
3. Identificeer en fix alle security/privacy issues
| Niveau | Fouten | Categorieën | Geschatte tijd |
|--------|--------|-------------|----------------|
| **Standaard** | 5 | Missing deps, typos, missing imports, inline styles → Tailwind | 1.5-2 uur |
| **Hard** | 12 | + logische fouten, React anti-patterns, useEffect bugs | 2-3 uur |
| **Super Hard** | 18 | + Next.js Server/Client, circular deps, TypeScript, Context | 3-4 uur |
**Uitgebreide README:**
- Wat AI genereerde
- Welke issues je vond (security, privacy, GDPR)
- Hoe je ze fixt
- Lessons learned
- Waarom WebStorm workflow beter/slechter is dan standalone OpenCode
Inleveren via Teams: GitHub link + screenshot + beschrijving van gefixt fouten.
Deadline: Vóór Les 4.
---
## Leerdoelen
Na deze les kan de student:
- Privacy risico's bij AI-gebruik identificeren
- Security vulnerabilities in AI-gegenereerde code herkennen
- GDPR/AVG compliance basics begrijpen
- WebStorm met OpenCode plugin configureren
- Het verschil tussen standalone en IDE-geïntegreerde workflow beoordelen
- Een persoonlijke AI Safety Checklist toepassen
- Cursor installeren en het Student Plan activeren
- Skills/Docs configureren voor Next.js, React en Tailwind
- Een .cursorrules bestand genereren via Cursor Chat
- Een nieuw Next.js project opzetten met npx create-next-app
- De keyboard shortcuts (Tab, Ctrl+K, Ctrl+L, Ctrl+I) toepassen
- Requests efficiënt beheren door taken te combineren
- Componenten bouwen met Composer en Inline Edit
- Fouten debuggen met behulp van Cursor

View File

@@ -1,131 +1,93 @@
# Les 4: Effectief Prompting, Iteratief Werken & Skills
> 📋 **Lesmateriaal nog niet uitgewerkt**
>
> De volgende bestanden worden gegenereerd wanneer deze les wordt uitgewerkt:
> - Les04-Slide-Overzicht.md
> - Les04-Lesplan.md
> - Les04-Bijlage-A-Lesopdracht.md
> - Les04-Bijlage-B-Huiswerkopdracht.md
# Les 4: TypeScript Fundamentals
---
## Hoofdstuk
**Deel 1: AI Foundations** (Les 1-4)
**Deel 2: Technical Foundations** (Les 4-9)
## Beschrijving
Geavanceerde prompt engineering technieken en introductie tot Skills.sh voor herbruikbare AI best practices.
Introductie tot TypeScript: waarom het waardevol is, hoe je types schrijft, en de basis die nodig is om straks React/Next.js te typen. Deel 1 van 2 TypeScript-lessen.
---
## Te Behandelen
### Groepsdiscussie (15 min)
Bespreek klassikaal de security/privacy bevindingen uit Les 3 - welke issues vonden jullie in AI-gegenereerde code? Hoe zien jullie AI Safety Checklists eruit?
### Waarom TypeScript? (15 min)
- Het probleem met JavaScript: runtime errors die je pas ziet als het te laat is
- Live demo: JS vs TS in Cursor — zelfde code, maar TS vangt fouten vooraf
- Voordelen: compile-time errors, betere autocomplete, zelf-documenterend, AI tools begrijpen getypte code beter
- TypeScript is de standaard: Next.js, React, alles is TypeScript
### Geavanceerde Prompt Engineering
- Zero-shot vs few-shot prompting
- Chain-of-thought reasoning
- Role prompting
- Constraint-based prompting
### Basic Types & Type Inference (15 min)
- Primitives: `string`, `number`, `boolean`
- Arrays: `number[]`, `string[]`, `Array<T>`
- Type inference: TypeScript raadt types vaak zelf
- Regel: annotate function parameters, laat TS de rest inferren
### Skills.sh Introductie
- Wat zijn Skills (herbruikbare best-practices packages)
- Hoe Skills werken (procedurele kennis voor AI agents)
- Skills installeren via CLI (`npx skills add <skill-name>`)
- Skills gebruiken in OpenCode/WebStorm
- Hoe Skills de kwaliteit verhogen zonder extra prompting
### Interfaces & Type Aliases (15 min)
- Interfaces: beschrijven de shape van objecten
- Optional properties met `?`
- Type aliases: `type Status = "pending" | "approved" | "rejected"`
- Union types en literal types
- Interface vs Type: wanneer welke?
### Iteratief Werken
- Start simpel → voeg complexiteit toe
- Context effectief gebruiken
### Functies & Errors (10 min)
- Function parameters en return types typen
- Veelvoorkomende TypeScript errors lezen en oplossen
- Hoe Cursor helpt met TypeScript errors (Cmd+K → fix)
---
## Tools
- OpenCode/WebStorm
- Skills.sh
- vercel-react-best-practices skill
- Cursor (Student Plan)
- TypeScript
- Node.js / ts-node
---
## Lesopdracht (2 uur)
## Lesopdracht (75 min)
### Deel 1: Skills Setup (30 min)
### TypeScript Escaperoom 🔐
**Installatie:**
- Installeer Skills CLI
- Add "vercel-react-best-practices" skill
Gamified TypeScript leerervaring met 8 "kamers" (puzzels):
**Vergelijking:**
- Bouw component ZONDER skill active
- Bouw zelfde component WITH skill active
- Zie het verschil in code quality
| Kamer | Concept | Moeilijkheid |
|-------|---------|--------------|
| 1 | Basic Types | ⭐ Makkelijk |
| 2 | Type Inference | ⭐ Makkelijk |
| 3 | Interfaces | ⭐⭐ Medium |
| 4 | Optional Properties | ⭐⭐ Medium |
| 5 | Union Types | ⭐⭐ Medium |
| 6 | Type Aliases | ⭐⭐ Medium |
| 7 | Functies Typen | ⭐⭐⭐ Moeilijk |
| 8 | Boss Room (alles samen) | ⭐⭐⭐ Moeilijk |
**Documenteer concrete verschillen:**
- Types
- Error handling
- Accessibility
- Performance patterns
### Deel 2: Iterative Build Challenge met Skills (1u 30min)
**Bouw data filtering systeem voor productlijst in 4 iteraties (~25 min elk):**
| Iteratie | Focus |
|----------|-------|
| 1 | Basis filter dropdown (category) |
| 2 | Meer filters (price range slider, brand checkboxes, rating stars) met Skills guidance |
| 3 | UX polish (clear all filters button, active filter chips, mobile responsive, loading states) |
| 4 | URL state management & advanced features (sorting, search) |
**Documenteer per iteratie:**
- Hoe hielpen Skills?
- Welke best practices werden automatisch toegepast?
Studenten fixen TypeScript code in elke kamer. Als alles compiled, krijgen ze de escape code: **TYPE-SAFE-CODE-LOCK-OPEN-DOOR-FREE-DOM!**
---
## Huiswerk (2 uur)
### Deel 1: Prompt Library (1 uur)
### JS → TypeScript Converter
Maak persoonlijke "prompt library" met 8 herbruikbare, geoptimaliseerde prompts voor:
1. Component creation
2. Bug fixing
3. Refactoring
4. Testing
5. API integration
6. Form validation
7. Responsive layout
8. Performance optimization
Studenten krijgen een werkend JavaScript project (4 bestanden: users, products, orders, utils) en moeten alles omzetten naar TypeScript:
**Vereisten:**
- Test elk met ChatGPT EN Claude
- Verfijn tot consistent goede output
- Format: Markdown document met prompt templates
- Interfaces schrijven voor alle objecten
- Union types voor statussen en categorieën
- Functies volledig typen
- Geen `any` toegestaan
- Tests (al in TypeScript) moeten slagen
### Deel 2: Skills Exploration (1 uur)
**Installeer 3 relevante Skills:**
1. "web-design-guidelines"
2. "frontend-design"
3. "supabase-postgres-best-practices" OF andere relevante skill
**Per skill:**
- Bouw klein component/feature met de skill active
- Documenteer wat de skill doet
- Concrete voorbeelden van hoe ze AI output beïnvloeden
**Bonus:** Bekijk "skill-creator" skill
**Delen:** Als GitHub gist
**Verificatie:** `npm run check` (0 errors) + `npm test` (alle tests groen)
---
## Leerdoelen
Na deze les kan de student:
- Geavanceerde prompt technieken toepassen (zero-shot, few-shot, chain-of-thought)
- Skills installeren en gebruiken
- Het verschil zien tussen output met en zonder Skills
- Iteratief werken (simpel → complex)
- Een persoonlijke prompt library opbouwen
- Uitleggen waarom TypeScript waardevol is voor developers
- Basic types gebruiken (string, number, boolean, arrays)
- Type inference begrijpen en toepassen
- Interfaces en type aliases schrijven
- Union types en literal types gebruiken
- Optional properties en functies typen
- TypeScript errors lezen en oplossen met Cursor

126
readme.md
View File

@@ -13,7 +13,7 @@ Een 18-weekse cursus die studenten meeneemt van AI-beginner naar AI-powered deve
| **v1** | Gegeven | Originele lessen (Les01, Les02 mappen) |
| **[v2](v2/)** | In ontwikkeling | Verbeterde lessen op basis van feedback |
**Feedback & Reflectie:** [v1-feedback.md](v1-feedback.md) - Bevindingen na het geven van les 1 en 2
**Feedback & Reflectie:** [v1-feedback.md](v1-feedback.md) - Bevindingen na het geven van les 1, 2 en 3
---
@@ -25,9 +25,9 @@ Een 18-weekse cursus die studenten meeneemt van AI-beginner naar AI-powered deve
|-----|-----------|------|--------|
| 01 | [Introductie tot AI en Large Language Models](Samenvattingen/Les01-Samenvatting.md) | 1 | ✅ Gegeven |
| 02 | [AI Code Assistants (OpenCode → Cursor)](Samenvattingen/Les02-Samenvatting.md) | 1 | ✅ Gegeven |
| 03 | [Cursor Setup & Basics](Samenvattingen/Les03-Samenvatting.md) | 1 | 🔨 In ontwikkeling |
| 04 | [Effectief Prompting, Iteratief Werken & Skills](Samenvattingen/Les04-Samenvatting.md) | 1 | 📋 Samenvatting |
| 05 | [TypeScript Basics](Samenvattingen/Les05-Samenvatting.md) | 2 | 📋 Samenvatting |
| 03 | [Cursor Setup & Basics](Samenvattingen/Les03-Samenvatting.md) | 1 | ✅ Gegeven |
| 04 | [TypeScript Fundamentals](Samenvattingen/Les04-Samenvatting.md) | 2 | 🔨 In ontwikkeling |
| 05 | [TypeScript voor React/Next.js](Samenvattingen/Les05-Samenvatting.md) | 2 | 📋 Samenvatting |
| 06 | [Next.js 1: Pages, Routing & Layouts](Samenvattingen/Les06-Samenvatting.md) | 2 | 📋 Samenvatting |
| 07 | [Next.js 2: Server Components & Data Fetching](Samenvattingen/Les07-Samenvatting.md) | 2 | 📋 Samenvatting |
| 08 | [Next.js 3: API Routes & Server Actions](Samenvattingen/Les08-Samenvatting.md) | 2 | 📋 Samenvatting |
@@ -48,8 +48,8 @@ Een 18-weekse cursus die studenten meeneemt van AI-beginner naar AI-powered deve
| Deel | Lessen | Tools | Kosten |
|------|--------|-------|--------|
| Deel 1: AI Foundations | 1-4 | ChatGPT, v0.dev, OpenCode, **Cursor** | Gratis (Cursor Student Plan) |
| Deel 2: Technical Foundations | 5-10 | TypeScript, Next.js, Supabase | Gratis |
| Deel 1: AI Foundations | 1-3 | ChatGPT, v0.dev, OpenCode, **Cursor** | Gratis (Cursor Student Plan) |
| Deel 2: Technical Foundations | 4-10 | TypeScript, Next.js, Supabase | Gratis |
| Deel 3: Full-Stack Development | 11-14 | Next.js, Supabase, Tailwind, **shadcn/ui**, Cursor | Gratis |
| Deel 4: Advanced AI & Deployment | 15-18 | Cursor, Vercel AI SDK, Vercel | Gratis (Cursor Student Plan) |
@@ -59,7 +59,7 @@ Een 18-weekse cursus die studenten meeneemt van AI-beginner naar AI-powered deve
# Deel 1: AI Foundations
**4 lessen · 7 EC**
**3 lessen · 5 EC**
Kennismaking met AI, LLMs en de basis van AI-assisted development met Cursor.
@@ -141,92 +141,104 @@ Kennismaking met AI, LLMs en de basis van AI-assisted development met Cursor.
### Les 3: Cursor Setup & Basics
**Tools:** Cursor, Git, GitHub
**Tools:** Cursor (Student Plan), Git, GitHub, Next.js, TypeScript, Tailwind CSS
**Docent vertelt:**
- Cursor overview: tab completion, inline edits, chat, composer
- Free tier vs Student Plan vs Pro
- Installatie en first-time setup
- Keyboard shortcuts: `Tab` (autocomplete), `Ctrl+K` (inline), `Ctrl+L` (chat), `Ctrl+Shift+L` (composer)
- AI model keuze: wanneer Haiku vs Sonnet?
- Privacy & security: hoe Cursor data behandelt
- `.cursorrules` introduceer: custom instructions voor je project
- Cursor overview: VS Code fork met AI, tab completion, inline edits, chat, composer
- Free vs Pro vs Student Plan (500 fast requests/maand)
- Request types en kosten: Tab = gratis, Chat/Composer/Inline Edit = 1 request
- Cursor Skills & Docs: framework documentatie toevoegen via Settings → Features → Docs
- .cursorrules genereren via Chat (1 request, goed besteed)
- Keyboard shortcuts: `Tab`, `Ctrl+K`, `Ctrl+L`, `Ctrl+I`
**Studenten doen:**
- **Groepsdiscussie:** Bespreek klassikaal ervaringen van vorige les - wat vond je van Cursor vs OpenCode?
- Cursor installeren en Student Plan activeren
- Een van je Les 2 projecten openen in Cursor
- Tab completion, Ctrl+K, en Ctrl+L uitproberen
- Begint `.cursorrules` bestand voor je project
- Terminal setup check (node, git, npm, npx)
- Cursor Student Plan activeren
- Nieuw project: git init → npx create-next-app@latest
- Skills/Docs configureren (Next.js, React, Tailwind)
- .cursorrules genereren via Chat
- Hands-on (75 min): Hero component bouwen, styling tweaken, extra feature toevoegen
- Git commit
**Lesopdracht:** Open je Les 2 project in Cursor, voeg 3 nieuwe features toe (elk met ander shortcut: Tab, Ctrl+K, Chat), test telkens of het werkt, noteer: welke shortcut voelt het nuttigst?
**Lesopdracht:** Bouw een nieuw Next.js project met Cursor: scaffold, configureer, bouw minimaal 2 componenten, commit.
**Huiswerk:** Experimenteer met Cursor Composer (Ctrl+Shift+L) op een bestaande component, schrijf reflectie (300 woorden) vergelijk je Cursor/OpenCode ervaringen, maak start-`.cursorrules` voor je eindproject.
**Huiswerk:** Debug Challenge — intentioneel kapot project fixen met Cursor. Drie niveaus: standaard (5 fouten), hard (12 fouten), super hard (18 fouten).
[→ Ga naar Les 3](Samenvattingen/Les03-Samenvatting.md)
**Lesmateriaal:**
- [Slide-Overzicht](Les03-Cursor-Basics/Les03-Slide-Overzicht.md)
- [Lesplan](Les03-Cursor-Basics/Les03-Lesplan.md)
- [Docenttekst](Les03-Cursor-Basics/Les03-Docenttekst.md)
- [Keynote Notes](Les03-Cursor-Basics/Les03-Docenttekst-Notes.md)
- [Lesopdracht](Les03-Cursor-Basics/Les03-Bijlage-A-Lesopdracht.md)
- [Huiswerkopdracht](Les03-Cursor-Basics/Les03-Bijlage-B-Huiswerkopdracht.md)
[→ Ga naar Les 3 Samenvatting](Samenvattingen/Les03-Samenvatting.md)
---
### Les 4: Effectief Prompting, Iteratief Werken & Skills
### Les 4: TypeScript Fundamentals
**Tools:** OpenCode/WebStorm, Skills.sh
**Tools:** Cursor (Student Plan), TypeScript, Node.js
**Docent vertelt:**
- Zero-shot vs few-shot prompting (met voorbeelden)
- Chain-of-thought reasoning: laat AI stap voor stap denken
- Role prompting en constraint-based prompting
- Skills.sh: wat het is en waarom het werkt
- Iteratief werken: start simpel → voeg complexiteit toe
- Waarom TypeScript? Het probleem met JavaScript runtime errors
- Live demo: JS vs TS in Cursor — zelfde code, maar TS vangt fouten vooraf
- Basic types: string, number, boolean, arrays
- Type inference: wanneer TypeScript types zelf raadt
- Interfaces en type aliases
- Union types en literal types
- Functies typen: parameters en return types
- Veelvoorkomende TypeScript errors lezen en oplossen
**Studenten doen:**
- **Groepsdiscussie:** Bespreek klassikaal ervaringen met OpenCode - wat werkte, wat niet?
- Verschillende prompt technieken uitproberen
- Skills.sh installeren en eerste skill toevoegen
- Vergelijk output met/zonder skill
- Bouw feature in 4 iteraties (simpel → complex)
- TypeScript Escaperoom: 8 kamers met type-puzzels van makkelijk naar moeilijk
- Elke kamer leert een concept (basics → inference → interfaces → unions → functies)
- Escape code ontgrendelen door alle type-errors te fixen
**Lesopdracht:** Installeer Skills.sh, vergelijk output met/zonder skill, bouw data filtering systeem in 4 iteraties (basis filter → multi-filter → sort → search).
**Lesopdracht:** TypeScript Escaperoom — los 8 kamers met TypeScript puzzels op. Gebruik Cursor's autocomplete en error fixing.
**Huiswerk:** Maak persoonlijke prompt library met 8 templates voor verschillende taken, installeer en test 3 Skills, documenteer concrete verschillen.
**Huiswerk:** JS → TypeScript Converter — zet een werkend JavaScript project (users, products, orders, utils) volledig om naar TypeScript. Tests (al in TS) moeten slagen.
[→ Ga naar Les 4](Samenvattingen/Les04-Samenvatting.md)
**Lesmateriaal:**
- [Slide-Overzicht](Les04-TypeScript-Fundamentals/Les04-Slide-Overzicht.md)
- [Lesplan](Les04-TypeScript-Fundamentals/Les04-Lesplan.md)
- [Docenttekst](Les04-TypeScript-Fundamentals/Les04-Docenttekst.md)
- [Lesopdracht](Les04-TypeScript-Fundamentals/Les04-Bijlage-A-Lesopdracht.md)
- [Huiswerkopdracht](Les04-TypeScript-Fundamentals/Les04-Bijlage-B-Huiswerkopdracht.md)
[→ Ga naar Les 4 Samenvatting](Samenvattingen/Les04-Samenvatting.md)
---
# Deel 2: Technical Foundations
**6 lessen · 10 EC**
**7 lessen · 12 EC**
Stevige technische basis: TypeScript, Next.js, databases en Supabase.
---
### Les 5: TypeScript Basics
### Les 5: TypeScript voor React/Next.js
**Tools:** OpenCode/WebStorm, TypeScript
**Tools:** Cursor, TypeScript, React, Next.js
**Docent vertelt:**
- Waarom TypeScript? Voordelen boven JavaScript
- Basic types: string, number, boolean, array, object
- Type inference: wanneer TypeScript types zelf raadt
- Interfaces en type aliases
- TypeScript met React: Props typen, useState met types
- TypeScript + React: props typen, useState met types
- Event handlers en callback types
- Generics basics (Array<T>, Promise<T>)
- Veel voorkomende TypeScript errors en hoe ze op te lossen
- API response types en async functies
- Type narrowing en utility types (Partial, Pick, Omit)
- JS naar TS omzetten in een React project
**Studenten doen:**
- JavaScript file omzetten naar TypeScript
- Interfaces schrijven voor eigen data
- React component met typed props maken
- TypeScript errors debuggen
- React components typen met interfaces
- useState en useEffect met types gebruiken
- Event handlers correct typen
- Bestaand React project omzetten naar TypeScript
**Lesopdracht:**
1. Zet bestaand JS component om naar TypeScript
2. Maak interface voor User en Product data
3. Bouw typed React component met props
4. Fix 5 TypeScript errors in gegeven code
**Lesopdracht:** Bouw getypte React componenten met Cursor. Type props, state, events en API responses.
**Huiswerk:** Maak 3 nieuwe components volledig in TypeScript, schrijf interfaces voor je eindproject data, maak cheat sheet met TypeScript patterns.
**Huiswerk:** Zet een compleet React project om van JavaScript naar TypeScript. Alle componenten, hooks en API calls volledig typen.
[→ Ga naar Les 5](Samenvattingen/Les05-Samenvatting.md)