From 63f84655e04af7084e3a2765998966e573884b91 Mon Sep 17 00:00:00 2001 From: Tim Rijkse Date: Mon, 2 Mar 2026 14:45:39 +0100 Subject: [PATCH] fix: lesson 4 --- .../Les04-Bijlage-A-Lesopdracht.md | 620 +++++++++ .../Les04-Bijlage-B-Huiswerkopdracht.md | 270 ++++ .../Les04-Docenttekst.md | 1236 +++++++++++++++++ .../Les04-Escaperoom-ANTWOORDEN.md | 629 +++++++++ .../Les04-Huiswerk-ANTWOORDEN.md | 562 ++++++++ .../Les04-Lesplan.md | 666 +++++++++ .../Les04-Slide-Overzicht.md | 772 ++++++++++ .../les4-huiswerk-js-converter.zip | Bin 0 -> 12003 bytes .../les4-typescript-escaperoom.zip | Bin 0 -> 14445 bytes Les04-TypeScript-Fundamentals/zi8nE7AW | Bin 0 -> 12891 bytes Samenvattingen/Les03-Samenvatting.md | 159 +-- Samenvattingen/Les04-Samenvatting.md | 148 +- readme.md | 126 +- 13 files changed, 4953 insertions(+), 235 deletions(-) create mode 100644 Les04-TypeScript-Fundamentals/Les04-Bijlage-A-Lesopdracht.md create mode 100644 Les04-TypeScript-Fundamentals/Les04-Bijlage-B-Huiswerkopdracht.md create mode 100644 Les04-TypeScript-Fundamentals/Les04-Docenttekst.md create mode 100644 Les04-TypeScript-Fundamentals/Les04-Escaperoom-ANTWOORDEN.md create mode 100644 Les04-TypeScript-Fundamentals/Les04-Huiswerk-ANTWOORDEN.md create mode 100644 Les04-TypeScript-Fundamentals/Les04-Lesplan.md create mode 100644 Les04-TypeScript-Fundamentals/Les04-Slide-Overzicht.md create mode 100644 Les04-TypeScript-Fundamentals/les4-huiswerk-js-converter.zip create mode 100644 Les04-TypeScript-Fundamentals/les4-typescript-escaperoom.zip create mode 100644 Les04-TypeScript-Fundamentals/zi8nE7AW diff --git a/Les04-TypeScript-Fundamentals/Les04-Bijlage-A-Lesopdracht.md b/Les04-TypeScript-Fundamentals/Les04-Bijlage-A-Lesopdracht.md new file mode 100644 index 0000000..d101f47 --- /dev/null +++ b/Les04-TypeScript-Fundamentals/Les04-Bijlage-A-Lesopdracht.md @@ -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(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! 🔓 diff --git a/Les04-TypeScript-Fundamentals/Les04-Bijlage-B-Huiswerkopdracht.md b/Les04-TypeScript-Fundamentals/Les04-Bijlage-B-Huiswerkopdracht.md new file mode 100644 index 0000000..3dcdafc --- /dev/null +++ b/Les04-TypeScript-Fundamentals/Les04-Bijlage-B-Huiswerkopdracht.md @@ -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(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 `` 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! 🚀 diff --git a/Les04-TypeScript-Fundamentals/Les04-Docenttekst.md b/Les04-TypeScript-Fundamentals/Les04-Docenttekst.md new file mode 100644 index 0000000..86d45e2 --- /dev/null +++ b/Les04-TypeScript-Fundamentals/Les04-Docenttekst.md @@ -0,0 +1,1236 @@ +# Les 4: TypeScript Fundamentals - Docenttekst + +## Lesgegevens + +| Aspect | Details | +|--------|---------| +| **Lesserie** | AI Developer Curriculum (NOVI Hogeschool) | +| **Lesnummer** | 4 van 18 | +| **Onderwerp** | TypeScript Fundamentals - Part 1 | +| **Duur** | 120 minuten (incl. pauze van 10 min) | +| **Doelgroep** | Beginners JavaScript/React, ervaring met Cursor | +| **Learning Outcomes** | Basis TypeScript begrip; types annoteren; interfaces/types definiëren; fouten lezen en begrijpen | +| **Voorgaande Les** | Les 3: Cursor als AI Code Editor (met debug challenges) | +| **Volgende Les** | Les 5: TypeScript + React (props, useState, event handlers) | + +--- + +## Context & Voorbereiding + +### Waarom Dit Moment in de Curriculum? + +In Les 3 hebben studenten **Cursor** leren kennen en hebben gezien hoe een AI-assistent code schrijft en debugt. Heel cruciaal: ze hebben gezien dat Cursor code in **TypeScript** schrijft, niet in gewone JavaScript. Dit is het perfecte moment om drie dingen duidelijk te maken: + +1. **TypeScript is standaard** — Niet iets exotisch. Next.js? TypeScript. React in 2026? TypeScript. Alle moderne web development? TypeScript. +2. **Types zijn geen luxury** — In Les 3 hebben ze AI-gegenereerde code debuggen. Types helpen daar massaal mee. +3. **De pijn voorkomen** — Runtime errors zijn heel pijnlijk. TypeScript vangt fouten VOORDAT je code runt. + +### Wat Weten de Studenten Al? + +Na Les 1-3 hebben studenten: +- Basiskennis **JavaScript** (variabelen, functies, arrays, objecten) +- Ervaring met **Cursor** en hoe het code genereert +- Inzicht in **debugging** (Les 3 hard challenge: bugs vinden in spaghetti code) +- Basis begrip van **React** (components, state, events) +- Gewend aan **code lezen en verstaan** + +Dit is een sterke basis. Ze snappen al hoe code werkt; nu leren ze hoe je **voorkómt** dat het fout gaat. + +### Lesdoel in Eén Zin + +"Begrijpen dat TypeScript fouten vroeg vangt, en kunnen basis types, interfaces en functies typen." + +### Praktische Setup + +Studenten hebben nodig: +- **Cursor** (al geïnstalleerd van Les 3) +- **Node.js** geïnstalleerd +- De **TypeScript Escaperoom** zip-file (zie Blok 6) + +Zelf als docent: +- Cursor open met een .js en .ts bestand side-by-side (voor live demo in Blok 2) +- TypeScript Escaperoom project klaar op je scherm +- Koppelingen naar moodle/Canvas voor huiswerk (Les 5) + +--- + +## Blok 1: Welkom & Terugblik (10 minuten) + +**Doel:** Energie creëren, Les 3 verbinden aan Les 4, het "why" instellen. + +### Openen (2 min) + +Kom de zaal in met energie. + +> "Goedemorgen! Goed om jullie weer te zien. Vorige week: debug challenge. Wie had de hard versie gedaan? Kom eens van je stoel!" + +Laat studenten die de hard versie hebben gedaan opstaan. Applaudisseer. Stel een paar korte vragen: + +- "Was het lastig? Ja? Precies. Hoe voelde het om die bugs te vinden?" +- "Hoeveel tijd hebben jullie eraan besteed?" + +Dit doet twee dingen: +1. Maakt duidelijk dat debugging work is (en TypeScript helpt daar tegen) +2. Bouwt community — iedereen snapt dat Les 3 pittig was + +### Terugblik: Van Cursor Naar TypeScript (5 min) + +> "Oké, vorige week jullie gezien hoe Cursor code schrijft. Cursor genereert code, jullie fixen bugs, alles werkt. Maar hier is de vraag: in welke TAAL schrijft Cursor? JavaScript?" + +Laat ze antwoorden. (Waarschijnlijk weten ze het niet zeker.) + +> "TypeScript! Alles wat Cursor schrijft — het is TypeScript. En jullie hebben heel soms `interface` gezien, `type` gezien, punt-punt-punt. Vandaag gaan we dát ontcijferen. Vandaag leren jullie TypeScript." + +Schrijf op het bord (of deel-screen): + +``` +Les 3: Cursor schrijft code (TypeScript) +Les 4: We begrijpen TypeScript (waarom? hoe?) +Les 5: We combineren TypeScript + React +``` + +### Vandaag's Plan (3 min) + +Deel het plan: + +**Eerste helft (tot 10:30):** +- Waarom TypeScript? (live demo!) +- Basic types +- Interfaces & Type Aliases +- Functies typen +- Intro TypeScript Escaperoom + +**Pauze (10 minuten)** + +**Tweede helft:** +- Jullie gaan aan de slag met de Escaperoom (75 minuten) +- Ik loop rond en help +- Afsluiting: recap, huiswerk, preview Les 5 + +> "Deze les is 50-50: theorie en praxis. Niet veel slides. Veel live coding, veel doen." + +**Energietip:** Dit moment lijkt klein, maar bepaalt de sfeer van de hele les. Je bent enthousiast, betrokken, duidelijk. Studenten volgen. + +--- + +## Blok 2: Waarom TypeScript? (15 minuten) + +**Doel:** Het "aha!" moment creëren. Studenten moeten voelen waarom TypeScript nodig is. + +### Setup: Live Demo in Cursor (5 min) + +Zorg dat je scherm zichtbaar is (beamer/Zoom share). Open Cursor. + +**Stap 1: Maak een .js bestand** + +```bash +touch demo.js +``` + +Open het en schrijf: + +```javascript +function greet(name) { + return "Hello, " + name.toUpperCase(); +} + +console.log(greet("tim")); +console.log(greet(42)); +``` + +> "Zie je dat? Een simpele functie. Twee keer aanroepen. Eén keer met een string, eén keer met het getal 42." + +Wacht, maak oogcontact. + +> "Vraag: ziet de editor een probleem?" + +(Waarschijnlijk niet — laat ze zien dat er geen rode squiggles zijn.) + +> "Nope. Geen error. Cursor denkt: alles oké." + +**Stap 2: Run het** + +```bash +node demo.js +``` + +Output: + +``` +Hello, TIM +TypeError: name.toUpperCase is not a function +``` + +> "KABOOM. Runtime error. Het werkt tot regel 7... dan crash. Waarom? Omdat 42 geen string is. 42 heeft geen `.toUpperCase()`." + +Maak weer oogcontact. + +> "Dat is het probleem met JavaScript. De editor ziet het niet aankomen. Pas TIJDENS het runnen snapt het: oh nee, fout." + +**Stap 3: Hetzelfde in TypeScript** + +```bash +mv demo.js demo.ts +``` + +(Of maak een nieuwe demo.ts.) + +Schrijf hetzelfde: + +```typescript +function greet(name) { + return "Hello, " + name.toUpperCase(); +} + +console.log(greet("tim")); +console.log(greet(42)); +``` + +> "Zelfde code. Nu TypeScript." + +Wacht. Kijk naar regel 5. + +> "Zie je dat? Rode squiggles onder 42. TypeScript zegt: nope, hier klopt iets niet." + +Click op de error: + +> "TypeScript zegt: 'Argument of type number is not assignable to parameter of type any.' Vertaald: je geeft een getal waar een string hoort." + +Nu fix het: + +```typescript +function greet(name: string) { + return "Hello, " + name.toUpperCase(); +} + +console.log(greet("tim")); +console.log(greet(42)); // RODE SQUIGGLE — METEEN ZICHTBAAR +``` + +> "Nu TypeScript ziet het DIRECT. Regel 5? Fout. Niet 'later als je runt'. NU AL. Dat is het superkracht van TypeScript." + +Run het: + +```bash +npx ts-node demo.ts +``` + +Output: + +``` +Hello, TIM +Error: Argument of type 'number' is not assignable to parameter of type 'string'. +``` + +Of beter: laat Cursor het fixen met Cmd+K: + +> "Kijk, ik klik op regel 5 met de error, ik druk Cmd+K, ik zeg 'fix this TypeScript error'..." + +Cursor suggereert: + +```typescript +function greet(name: string): string { + return "Hello, " + name.toUpperCase(); +} + +console.log(greet("tim")); +// console.log(greet(42)); // removed this problematic call +``` + +> "Cursor snapt het probleem en fixes het. Maar het belangrijke: TypeScript vangt het VOORDAT je code runt." + +### De 4 Voordelen van TypeScript (8 min) + +Nu de theorie. Schrijf dit op (of deel-screen): + +``` +1. Fouten VROEG vangen +2. Betere autocomplete & IDE ondersteuning +3. Code wordt zelf-documenterend +4. AI tools snappen het beter +``` + +#### 1. Fouten VROEG Vangen + +> "Zoals je net zag. In JavaScript: fouten in runtime. In TypeScript: fouten in je editor. Veel sneller feedback loop." + +**Voorbeeld:** + +```typescript +const user = { name: "Anna", age: 25 }; +console.log(user.emali); // RODE SQUIGGLE — typo in 'email' +``` + +TypeScript ziet meteen: `Property 'emali' does not exist on type '{ name: string; age: number; }'`. + +> "Stel je voor: je hebt een functie met 100 regels. Ergens zit een typo. In JavaScript: je runt het en het breekt 3 uur later in productie. In TypeScript: je ziet het meteen in je editor." + +#### 2. Betere Autocomplete + +Demo in Cursor. Maak een user object: + +```typescript +const user = { + name: "Tim", + email: "tim@novi.nl", + isStudent: true, + courses: ["TypeScript", "React"] +}; + +// Nu typ: user. +``` + +Laat ze zien dat als je `user.` typt, Cursor METEEN alle properties suggereert: + +``` +name +email +isStudent +courses +``` + +> "Zien? TypeScript weet EXACT welke properties `user` heeft. Cursor autocomplete? Ongelofelijk. Geen typos, geen raden." + +In JavaScript zou Cursor veel minder weten. + +#### 3. Code Wordt Zelf-Documenterend + +```typescript +// Slechts JavaScript: +function createUser(id, name, email) { + return { id, name, email }; +} + +// TypeScript: +interface User { + id: number; + name: string; + email: string; +} + +function createUser(id: number, name: string, email: string): User { + return { id, name, email }; +} +``` + +> "Zie je? De TypeScript versie: meteen duidelijk. Welke types gaan erin? Wat komt eruit? Geen giswerk. Je leest het." + +#### 4. AI Tools Snappen het Veel Beter + +Dit is belangrijk voor hun toekomst. + +> "Jullie gaan Cursor gebruiken. ChatGPT gebruiken. En die tools? Die snappen TypeScript VEEL beter dan plain JavaScript. Als je Cursor zegt 'maak een React component', en je hebt types, Cursor genereert meteen beter code. Minder bugs, betere structuur." + +### Context: Dit is de Standaard (2 min) + +> "Quick reality check. Werken jullie straks bij een bedrijf dat niet TypeScript gebruikt? Nee. Nou ja, misschien als het heel erg legacy is. Maar alles moderne? Next.js, React, Angular, Vue — standaard TypeScript. Niet optioneel. Standaard." + +Rondkijken. + +> "Dus: dit is niet iets grappigs wat we vandaag leren. Dit is wat je GAAT gebruiken. Elk project. Elk jaar. Goed om het nu al begrepen te hebben." + +--- + +## Blok 3: Basic Types & Type Inference (15 minuten) + +**Doel:** Studenten kunnen basis types annoteren en begrijpen type inference. + +### Live Coding: Basis Types (8 min) + +Open Cursor. Nieuw bestand: `types-demo.ts`. + +> "Oké, eerst basics. Wat zijn types?" + +Schrijf: + +```typescript +let name: string = "Tim"; +let age: number = 25; +let isStudent: boolean = true; +``` + +> "Dit zijn de drie basis types: string, number, boolean. Super eenvoudig. Je zegt: 'Deze variable, het is een string.' TypeScript zegt: 'Oké, onthouden.'" + +Laat zien: + +```typescript +let name: string = "Tim"; +name = 42; // RODE SQUIGGLE +``` + +> "Als je later probeert 42 in `name` te stoppen, TypeScript zegt: nope, name is string, geen number." + +Nu arrays: + +```typescript +let scores: number[] = [90, 85, 88]; +let tags: string[] = ["typescript", "react", "javascript"]; +``` + +> "Arrays zijn hetzelfde. `number[]` betekent: een array van numbers. Alleen nummers erin." + +Demo: + +```typescript +let scores: number[] = [90, 85, 88]; +scores.push("oops"); // RODE SQUIGGLE +``` + +Laat zien wat TypeScript zegt: `Argument of type 'string' is not assignable to parameter of type 'number'`. + +### Type Inference: TypeScript is Slim (5 min) + +Nu het interessante deel. + +```typescript +let message = "Hello"; +``` + +> "Geen type annotering. Maar kijk..." + +Hover over `message` in je editor. Tooltip verschijnt: + +``` +(let) message: string +``` + +> "TypeScript weet het al! Zonder dat ik het zei. Omdat ik "Hello" toewijzig — een string — TypeScript snapt: oh, dit is een string variable." + +Dit heet **type inference**. + +```typescript +let count = 5; // TypeScript: number +let active = true; // TypeScript: boolean +let items = [1, 2, 3]; // TypeScript: number[] +``` + +> "Dit is geniaal. Je hoeft niet ALLES te typen. TypeScript is slim genoeg om het zelf uit te vogelen." + +### Rule of Thumb: Wanneer Annoteren? (2 min) + +> "Dus: moet je alles typen?" + +Antwoord: + +**Ja typen:** +- **Function parameters** — altijd +- **Function return types** — altijd (of laat TypeScript infer als het duidelijk is) + +**Nee typen:** +- **Variable assignments** — let TypeScript infer, tenzij het onduidelijk is + +```typescript +// GUT: +function add(a: number, b: number): number { + return a + b; +} + +const result = add(5, 3); // TypeScript weet: result is number + +// SLECHT: +const result: number = add(5, 3); // Redundant +``` + +> "Onthoud: functies typen is verplicht. Variables? Let TypeScript denken." + +--- + +## Blok 4: Interfaces & Type Aliases (15 minuten) + +**Doel:** Studenten kunnen objecten beschrijven met interfaces en type aliases. + +### Interfaces: De SHAPE van Objecten (7 min) + +> "Wat als je een object hebt? Hoe beschrijf je dat?" + +Live demo: + +```typescript +interface User { + id: number; + name: string; + email: string; +} + +const user: User = { + id: 1, + name: "Anna", + email: "anna@novi.nl" +}; +``` + +> "Interface zeggen: 'Een User object heeft PRECIES deze properties, met DEZE types.' Niks meer, niks minder." + +Demo de autocomplete: + +```typescript +const user: User = { + // Typ hier... + // Cursor suggereert: id, name, email +}; + +// Later: +user.id; // number +user.name; // string +user.email; // string +user.phone; // RODE SQUIGGLE — bestaat niet +``` + +> "Zien? Cursor weet: User heeft deze velden. Alleen deze. Geen typos." + +### Optional Properties (2 min) + +```typescript +interface User { + id: number; + name: string; + email: string; + phone?: string; // OPTIONEEL +} + +const user1: User = { + id: 1, + name: "Anna", + email: "anna@novi.nl" + // phone niet nodig +}; + +const user2: User = { + id: 2, + name: "Bob", + email: "bob@novi.nl", + phone: "+31612345678" +}; +``` + +> "Het `?` betekent optional. Misschien heb je een phone, misschien niet. TypeScript accepteert beide." + +### Type Aliases: Union Types (4 min) + +Interfaces zijn voor objecten. Maar wat als je iets anders wilt typen? + +```typescript +type Status = "pending" | "approved" | "rejected"; + +const order: Status = "pending"; // ✓ oké +const order: Status = "shipped"; // RODE SQUIGGLE +``` + +> "Type aliases: je definieert een naam voor iets. Hier: Status kan ALLEEN deze drie strings zijn. Niet willekeurig. DEZE drie." + +Dit heet **union type** — een waarde kan ÉÉN van verschillende opties zijn. + +```typescript +type Response = string | number | boolean; + +const answer: Response = "yes"; // ✓ +const answer: Response = 42; // ✓ +const answer: Response = true; // ✓ +const answer: Response = {}; // RODE SQUIGGLE — object mag niet +``` + +### Interface vs Type: Wat is het Verschil? (2 min) + +Dit is een veel gestelde vraag. Hou het simpel: + +> "Interface of Type? Goeie vraag. Praktisch antwoord: **Interface voor objecten. Type voor alles anders.**" + +```typescript +// Interface +interface User { + id: number; + name: string; +} + +// Type — alles ander +type Status = "pending" | "approved" | "rejected"; +type ID = number | string; +type Config = { host: string; port: number }; +``` + +> "Eerlijk? Voor 90% van wat jullie gaan doen, is het niet superkritiek. Kies er één en wees consistent. Ik zeg: interview voor objects, type voor alles. Maar je docent volgende week zegt: altijd type. Both zijn oké." + +**Key insight:** + +> "Belangrijk: beide zijn TypeScript. Allebei geven TypeScript dezelfde informatie. Het is 'preference'." + +--- + +## Blok 5: Functies & Fouten (10 minuten) + +**Doel:** Studenten kunnen functies typen en herkennen veel voorkomende TypeScript fouten. + +### Functies Typen (4 min) + +```typescript +// Regular function +function add(a: number, b: number): number { + return a + b; +} + +// Arrow function +const multiply = (a: number, b: number): number => a * b; + +// With console.log (return type: void) +function logUser(user: User): void { + console.log(user.name); +} + +// Optional parameters +function greet(name: string, greeting?: string): string { + return greeting ? greeting + ", " + name : "Hello, " + name; +} +``` + +> "Pattern: types IN (parameters), type OUT (return type). Altijd. Functies zijn waar types het meest helpen." + +### Veel Voorkomende TypeScript Fouten (6 min) + +Studenten zullen deze zien. Laat ze kennen: + +#### Fout 1: Type 'X' is not assignable to type 'Y' + +```typescript +let count: number = "hello"; // RODE SQUIGGLE +// Type 'string' is not assignable to type 'number' +``` + +> "Vertaald: je probeert een string in iets te stoppen dat number moet zijn. Mismatch." + +Fix: zorg dat het type klopt. + +```typescript +let count: number = 5; // ✓ +``` + +#### Fout 2: Property 'X' does not exist on type 'Y' + +```typescript +const user = { name: "Tim", age: 25 }; +console.log(user.emali); // RODE SQUIGGLE +// Property 'emali' does not exist +``` + +> "Typo. Je schreef 'emali' maar het property heet 'email'." + +Fix: spel het goed. + +```typescript +console.log(user.email); // ✓ (als het property bestaat) +``` + +#### Fout 3: Object is possibly 'undefined' + +```typescript +function getUser(): User | undefined { + // misschien geeft dit undefined terug +} + +const user = getUser(); +console.log(user.name); // RODE SQUIGGLE +// Object is possibly 'undefined' +``` + +> "TypeScript zegt: dit kan undefined zijn. Je mag niet zomaar `.name` eroppen. Wat als het undefined is?" + +Fix: check eerst: + +```typescript +const user = getUser(); +if (user) { + console.log(user.name); // ✓ nu weet TypeScript: user is niet undefined +} +``` + +### Cursor Helpt (1 min) + +> "Deze fouten gaan jullie VEEL tegenkomen. Dat is GOED! TypeScript beschermt je." + +En Cursor helpt ook: + +> "Als je een rode squiggle ziet, plaats je cursor erop, druk Cmd+K (Command+K op Mac), en zeg: 'fix this error' of 'explain this error'. Cursor geeft uitleg en suggesties." + +--- + +## Blok 6: Hands-On Intro — TypeScript Escaperoom (5 minuten) + +**Doel:** Context voor de praktijkles. Studenten snappen wat ze gaan doen. + +### Wat is de Escaperoom? + +> "Oké, theorie klaar. Nu gaan jullie zelf TypeScript leren door TE DOEN." + +Toon op je scherm (of deel-screen) een preview van het project: + +``` +TypeScript Escaperoom +├── Room 1: Basic Types +├── Room 2: Interfaces +├── Room 3: Type Inference +├── Room 4: Functions +├── Room 5: Union Types +├── Room 6: Optional Properties +├── Room 7: Function Overloading +└── Room 8: Challenge Room + +GOAL: Solve all 8 rooms, collect the escape code +``` + +> "Het concept: 8 kamers. Elke kamer heeft TypeScript puzzels. Jij lost ze op. Als je een kamer good solved, krijg je een escape code fragment. Alle 8 fragments bij elkaar? Je hebt het escape code." + +### Hoe Werkt het? + +> "Je opent een TypeScript bestand. Er staan 'take mee comment' in. Jij vult aan wat ontbreekt. Je runt het. TypeScript compiler zegt: 'Fout!' of 'Oké!' Als het oké is, je krijgt een code. Die codes samelen naar het einde toe." + +Voorbeeld tonen: + +```typescript +// Room 1: Basic Types +// TODO: Create a variable 'age' of type number and assign it the value 25 +// TODO: Create a variable 'name' of type string and assign it "Alice" +// TODO: Create a variable 'isActive' of type boolean and assign it true + +// Solution: +let age: number = 25; +let name: string = "Alice"; +let isActive: boolean = true; + +// If correct, you'll see: ESCAPE_CODE_1: ABC123XYZ +``` + +### Setup Instructions (2 min) + +> "Stappen om aan de slag te gaan:" + +Schrijf dit op (of deel-screen): + +1. **Download de zip**: [link naar moodle/Canvas] +2. **Extract het**: `unzip typescript-escaperoom.zip` +3. **Open in Cursor**: `cursor .` (in de folder) +4. **Install packages**: `npm install` +5. **Begin met kamer 1**: Open `room-1.ts` +6. **Lees de TODOs**, vul aan, spaar op (Ctrl+S of Cmd+S) +7. **Run**: `npm run room:1` (of wat de instructie zegt) +8. **Escape code?** Als je het goed hebt: je krijgt een code te zien + +> "Alle 8 kamers doen? Einde van de les heb je het master escape code." + +### Tips & Tricks (2 min) + +> "Paar tips terwijl je aan het werk bent:" + +1. **Hover over errors** — plaats je cursor op een rode squiggle, en je ziet uitleg +2. **Autocomplete is je vriend** — als je iets typt, Cursor suggereert. Gebruik het! +3. **Cursor Cmd+K** — als je echt vast zit, plaats cursor op error, druk Cmd+K, zeg: "explain this TypeScript error" of "fix this" +4. **Denk eerst zelf** — probeer EERST zelf uit te vogelen. Pas dan vragen stellen of Cursor om hulp vragen. +5. **Leesfouten** — de TODOs zijn heel precies. Lees goed wat je moet doen. + +> "Vragen? Ik loop rond. Steek je hand op." + +--- + +## PAUZE (10 minuten) + +Studenten gaan naar buiten / hebben een break. Jij: +- Zorg dat je scherm klaar is voor de volgende ronde +- Controleer je eigen laptop/connectie +- Heb de Escaperoom zip klaar +- Bereid je voor op rondlopen (notieblok, pen) + +--- + +## Blok 7: Hands-On Praktijk (75 minuten) + +**Doel:** Studenten werken aan de TypeScript Escaperoom. Jij helpt, observeert, stimuleert. + +### Opzet (0-5 min) + +> "Welkom terug. Iedereen klaar? Download de zip, extract, `npm install`, open in Cursor?" + +Zorg dat iedereen de eerste room open heeft. Start hen allemaal op hetzelfde moment: + +> "We starten met Room 1 op hetzelfde moment. 3... 2... 1... GO!" + +### Rondlopen & Helpen (5-70 min) + +Nu is het jouw taak om: + +#### A. Observeren +Walk door de zaal. Kijk naar schermen. Wie zit vast? Wie is snel klaar? + +#### B. Helpen (zonder ant te geven!) + +Dit is BELANGRIJK. Je helpt, maar je geeft niet de antwoord. + +**Voorbeeld — student zit vast op Room 3:** + +❌ FOUT: +> "Oké, je schrijft `let age: string = 25;` — nee, dit is fout. Je moet `number` schrijven, niet `string`." + +✓ GOED: +> "Oké, laten we kijken. De TODO zegt: 'Create age of type number.' Wat zegt TypeScript nu? Kijk op je scherm... ah, zie je dat: 'Type string is not assignable to type number.' Wat denk jij: is 25 een string of een number?" + +Student: "Oh, 25 is een number!" + +> "Precies. Dus welk type moet age zijn?" + +Student: "Number!" + +> "Yes! Probeer het." + +Dit is Socratisch onderwijs. Je stelt vragen, student vindt antwoord. + +#### C. Stimuleren + +**Voor trage studenten:** +- Halveway Room 3 (rond 11:00), check: "Hoe gaat het? Stuck? Laten we naar de error kijken. Wat zegt TypeScript?" +- Rond 11:30: "Je bent op Room 4. Goed! Volgende." + +**Voor snelle studenten:** +- Rond 10:45: "Helemaal klaar? Nice! Hier: bonus challenge." (zie hieronder) +- Zorg dat ze niet *wachten* — ze kunnen altijd meer leren. + +#### D. Veelvoorkomende Problemen & Oplossingen + +**Probleem 1: "Ik snap niet wat de TODO vraagt"** + +Lees de TODO samen met de student hardop voor. Zeg in je eigen woorden wat het vraagt. Een TODO als: + +```typescript +// TODO: Create an interface User with properties id (number), name (string), email (string) +``` + +Jij: "Dus: je maakt een interface. Het heet User. Het heeft drie properties: id die een number is, name die string is, email die string is. Wat schrijf je?" + +**Probleem 2: "Ik krijg rood overal, ik snap het niet"** + +> "Laten we stap voor stap gaan. Wat is de EERSTE rode squiggle?" + +Focus op één fout tegelijk. + +**Probleem 3: "Kan ik Cursor gebruiken om dit op te lossen?"** + +Ja, maar: + +> "Je mag Cursor Cmd+K gebruiken om het uit te leggen of te fixen. Maar: probeer EERST zelf. Cursor is je trainer, niet je antwoordboek." + +**Probleem 4: "Ik ben in een ander room en ik snap er niks van"** + +> "Laten we teruggaan naar Room 5 of 6 (wat je wél snapte). Wat zat daar? Oké, dit room is hetzelfde idee, maar..." + +Haak aan bij wat ze al kennen. + +### Check-in Momenten + +Plan drie korte check-ins: + +**10:45 — Eerste Check (halveway)** +- Iedereen op Room 2 of 3? +- Wie has probleem en waar? +- Energieniveau OK? + +Bijvoorbeeld: + +> "Iedereen, 2 seconden. Hoe ver zijn we? Room 1? 2? Mooi! Wie zit vast? [student steekt hand op] Laten we daar even naar kijken." + +**11:00 — Tweede Check** +- Iedereen voortgang? +- Zijn studenten "stuck in a loop" (dezelfde error, keer op keer)? + +**11:30 — Laatste Check** +- 15 minuten tot einde. Wie is klaar? Wie heeft nog 1-2 kamers? +- Snelle studenten: "Alle 8 gedaan? Epic! Hier extra challenge." + +### Bonus Challenges (voor Snelle Studenten) + +Voor studenten die alle 8 kamers hebben gedaan (normaal zijn dit de snelsten): + +**Bonus 1: Generics** (gaat verder dan les 4) +```typescript +// Create a generic function that works with any type +function getFirstElement(arr: T[]): T { + return arr[0]; +} + +const first = getFirstElement([1, 2, 3]); // number +const firstStr = getFirstElement(["a", "b"]); // string +``` + +**Bonus 2: Advanced Interfaces** +```typescript +// Inheritance & extending +interface Animal { + name: string; +} + +interface Dog extends Animal { + breed: string; +} +``` + +**Bonus 3: Type Guards** +```typescript +function processInput(input: string | number) { + if (typeof input === "string") { + console.log(input.toUpperCase()); + } else { + console.log(input + 10); + } +} +``` + +Zeg: +> "Dit is Les 5 material. Maar je bent snel. Probeer het. Vraag Cursor!" + +### Energy Management + +Dit is een lange blok (75 min). Zorg voor energie: + +- **Rond 11:15**: "Iedereen, 30 seconden stretchen. Sta op als je zit." +- **Rond 11:35**: "Laatste 10 minuten! Zet ineens aan!" + +--- + +## Blok 8: Afsluiting (15 minuten) + +**Doel:** Recap, validatie, huiswerk, toekomst. + +### Wie Heeft het Escape Code? (3 min) + +> "Oké, allen! Wie heeft het complete escape code? Alle 8 kamers?" + +Laat studenten hun code tonen. Applaudisseer. + +> "Nice! Goed werk. Wie 6 kamers gedaan? 5? 4? Allemaal goed! Volgende week maken jullie het af, en dan gaan we dieper." + +### Snelle Recap: De 3 Key Takeaways (5 min) + +Zet dit op het bord (of deel-screen): + +``` +1. Types voorkomen RUNTIME ERRORS +2. Interfaces beschrijven OBJECTEN +3. Functies ALTIJD typen +``` + +Ga door elk: + +**1. Types voorkomen runtime errors** +> "Onthouden: je JavaScript code kan 3 uur later breken in productie. TypeScript zagt: nope, hier is het fout, FIX het NU. In je editor." + +**2. Interfaces beschrijven objecten** +> "Object nodig? Interface. Object zegt: dit object heeft deze form. Dit property, deze type. Cursor gebruikt het om je te helpen." + +**3. Functies ALTIJD typen** +> "Rule: functie parameters IN, functie return type OUT. Altijd annoteren. Variables? Let TypeScript infer. Maar functies? Altijd." + +### Huiswerk (4 min) + +> "Huiswerk voor volgende week:" + +Schrijf op (en stuur ook via email/Canvas): + +``` +HW Les 4: +1. Finish all 8 TypeScript Escaperoom rooms (if not done today) +2. Document your escape code in a .txt file +3. Prepare for Les 5: we combine TypeScript with React + - Read: React + TypeScript basics (link in Canvas) + - Think: How would you type React props? +``` + +> "Room 1-8 moet af. Als je niet klaar bent vandaag, je hebt de week om het af te maken. Volgende week bouw je hierop voort." + +### Preview Les 5: TypeScript + React (3 min) + +> "Volgende week: Les 5. Wat gaan we doen?" + +Schrijf op: + +``` +Les 5: TypeScript + React +- Typing React Props +- useState with Types +- Event Handlers +- Building a small React project with TS +``` + +> "Jullie weten nu: types voorkomen fouten. Functies typen. Interfaces. Volgende week: React components. Props zijn... functies. Dus: props typen. useState? Het returned state EN een setter — beide getypd. Events? Handlers getypd." + +> "TypeScript + React = superkracht. Cursor snapt je code beter. Minder bugs. Betere autocomplete." + +### Slotwoord (Energie) (1 min) + +Oogcontact, glimlach. + +> "Jullie hebben vandaag veel geleerd. TypeScript lijkt misschien veel, veel rules. Maar denk eraan: elke rode squiggle is TypeScript die zegt: 'Hé, ik help je.' Not iets what pissed off is. It's helpful." + +> "Volgende week nog beter. Vragen? Slack, email, ik ben er. Goed gedaan vandaag." + +Applaus. + +--- + +## Praktische Tips voor de Docent + +### Setup Checklist (Voor Jezelf) + +- [ ] Cursor geïnstalleerd en werkt +- [ ] Twee voorbeeldbestanden klaar: demo.js en demo.ts (voor Blok 2) +- [ ] TypeScript Escaperoom zip klaar om te delen +- [ ] Npm install hebben gedaan in de escaperoom (opdat je het kunt runnen) +- [ ] Beamer/screen sharing testen +- [ ] Audio testen (voor demos) +- [ ] Een backup plan: als iemand's installatie niet werkt, heb jij hem al draaien + +### Energie en Ritme + +**Sterke openers:** +- "Vorige week: debug challenge. Wie had het super lastig?" +- "TypeScript. Klinkt ingewikkeld. Is het niet." +- "Fout vangen VOORDAT je code runt. Dat is de superpower." + +**Momentum behouden:** +- Niet te veel slides. Veel live demo. +- Move rond terwijl je praat. Niet statisch. +- Maak oogcontact. Glimlach. Show enthousiasme. + +**Energiedalingen voorkomen:** +- Na live demo (10 min) → iedereen doet iets (hands-on start) +- Pauze op juiste moment (na 55 min) +- Check-ins om focus terug te krijgen + +### Veelgestelde Studentenvragen + +**Q: "Waarom TypeScript en niet JavaScript?"** +A: "JavaScript is oké voor kleine projecten. TypeScript is oké voor alles, groot en klein. En alle moderne bedrijven gebruiken TypeScript. Future-proofing." + +**Q: "Moet ik elk variable typen?"** +A: "Nee. Functies: ja. Variables: let TypeScript infer, tenzij onduidelijk. Thumb rule: minder typen = minder code, zelf TypeScript doet het werk." + +**Q: "Interface of Type?"** +A: "90% van het moment: maakt niet uit. Kies er één, wees consistent. Ik zeg: interface voor objects, type voor alles. Maar beide zijn oké." + +**Q: "Kan ik Cursor gebruiken?"** +A: "Ja! Zeker! Maar: denk EERST zelf. Cursor is trainer, niet antwoordboek. Denk 5 min, dan Cursor als je vast zit." + +**Q: "Dit is heel veel regels..."** +A: "Ja, TypeScript has veel regels. Maar: elke regel beschermt je. Elke regel voorkomt bugs. Waard." + +### Troubleshooting + +**Probleem: Npm install faalt** +- Check: `node -v` en `npm -v` installed? +- Als niet: snel tutorial of use Cursor terminal +- Als ja: `npm cache clean --force` en retry + +**Probleem: Cursor opens niet** +- Reboot? +- Reinstall? +- Fallback: VS Code (gratis, heeft ook TypeScript support) + +**Probleem: TypeScript compiler errors maken niemand blij** +- Normalize het: "Dit is GOED. Dit is TypeScript wat je beschermt." +- Laat zien: hetzelfde in JavaScript zou crash zijn in productie. + +**Probleem: Iemand is ECHT vast en depressed** +- One-on-one. Lees de TODO samen. Stap voor stap. +- "Dit IS lastig. First time TypeScript. Normal dat je vast zit." +- Geef niet het antwoord; guide ze. +- Zeg: "Room 7-8 is bonus. Finish 1-6, je bent golden." + +--- + +## Post-Les Checklist + +**Direct na de les:** +- [ ] Weet jij wie alle 8 kamers gedaan heeft? +- [ ] Noteer eventuele "stuck" punten (welke kamers waren lastig?) +- [ ] Hoe was energie? (1-10?) +- [ ] Feedback verzamelen (ask a few: "Wat was het lastigst vandaag?") + +**Voorbereiding Les 5:** +- [ ] Huiswerk controleren (wie heeft Escaperoom afgemaakt?) +- [ ] React + TypeScript slides/demo voorbereiding +- [ ] Props-typing voorbeeld code klaar +- [ ] useState example met types klaar +- [ ] Event handler examples klaar + +--- + +## Samenvatting Lesdoelen + +Na deze les kunnen studenten: + +✅ **Begrijpen waarom TypeScript nodig is** +- Runtime errors voorkomen +- Betere IDE ondersteuning +- Code zelf-documenterend +- AI tools helpen beter + +✅ **Basis types annoteren** +- `string`, `number`, `boolean` +- Arrays: `number[]`, `string[]` +- Type inference snappen + +✅ **Interfaces en Types definiëren** +- Interface voor object shapes +- Type voor unions en andere +- Optional properties + +✅ **Functies typen** +- Parameters in, return type out +- Arrow functions +- Void return type + +✅ **TypeScript errors lezen en begrijpen** +- Type mismatch errors +- Property not exist errors +- Possibly undefined errors + +✅ **Cursor gebruiken voor TypeScript hulp** +- Hover over errors +- Cmd+K voor explain/fix + +--- + +## Notes voor Toekomstige Lessen + +**Les 5 Building Blocks:** +- Type deze les: studenten kennen `interface`, `type`, basis annoteren +- React Props: `interface Props { name: string; age: number; }` — students get it +- useState: `const [count, setCount] = useState(0)` — students know generics from this prep + +**Les 6+ Context:** +- TypeScript is nu het water dat iedereen in zwemt +- Alle code is getypd +- Students expect autocomplete + +--- + +## Appendix: Code Snippets Klaar + +Hier zijn alle code snippets voor de les, klaar om te copy-pasten: + +### Blok 2 Demo +```javascript +// demo.js +function greet(name) { + return "Hello, " + name.toUpperCase(); +} + +console.log(greet("tim")); +console.log(greet(42)); +``` + +```typescript +// demo.ts +function greet(name: string): string { + return "Hello, " + name.toUpperCase(); +} + +console.log(greet("tim")); +// console.log(greet(42)); // TypeScript error +``` + +### Blok 3 Types +```typescript +let name: string = "Tim"; +let age: number = 25; +let isStudent: boolean = true; + +let scores: number[] = [90, 85, 88]; +let tags: string[] = ["typescript", "react"]; + +let message = "Hello"; // type inference: string +let count = 5; // type inference: number + +function add(a: number, b: number): number { + return a + b; +} + +const result = add(5, 3); // type inference: number +``` + +### Blok 4 Interfaces & Types +```typescript +interface User { + id: number; + name: string; + email: string; + phone?: string; +} + +const user: User = { + id: 1, + name: "Anna", + email: "anna@novi.nl" +}; + +type Status = "pending" | "approved" | "rejected"; +type Response = string | number | boolean; + +const orderStatus: Status = "pending"; +const answer: Response = 42; +``` + +### Blok 5 Functions & Errors +```typescript +// Regular function +function add(a: number, b: number): number { + return a + b; +} + +// Arrow function +const multiply = (a: number, b: number): number => a * b; + +// Void return +function logUser(user: User): void { + console.log(user.name); +} + +// Optional parameters +function greet(name: string, greeting?: string): string { + return greeting ? greeting + ", " + name : "Hello, " + name; +} + +// With type guard +function getUser(): User | undefined { + // ... +} + +const user = getUser(); +if (user) { + console.log(user.name); // ✓ safe +} +``` + +--- + +## Aantekeningen en Reflectie + +**Na de les: Noteer:** +- Welke moment waren studenten het meest engaged? +- Welke kamers/onderdelen waren lastig? +- Wie heeft extra hulp nodig volgende week? +- Wat ging goed? Wat zou je volgende keer anders doen? + +**Voorbeeld reflectie:** +- "Room 7 (function overloading) was te moeilijk. Next time: skip dat en zeg 'Les 6'." +- "Live demo in Blok 2 was superkrachtig — 5 min voor runtime error echt wow moment." +- "3 studenten stil achter. 1-op-1 help. Next time: meer pair programming?" + +--- + +## Einde Docenttekst + +Dit is je complete guide voor Les 4. Je hebt alles wat je nodig hebt: +- Wat je gaat zeggen (gedetailleerd) +- Hoe je het gaat doen (live demos) +- Code om te gebruiken +- Praktische tips +- Troubleshooting + +Veel sterkte! TypeScript is een game changer voor je studenten. Ze zullen het voelen. + +**Vragen? Contact me. Goed onderwijzen!** diff --git a/Les04-TypeScript-Fundamentals/Les04-Escaperoom-ANTWOORDEN.md b/Les04-TypeScript-Fundamentals/Les04-Escaperoom-ANTWOORDEN.md new file mode 100644 index 0000000..c183fdc --- /dev/null +++ b/Les04-TypeScript-Fundamentals/Les04-Escaperoom-ANTWOORDEN.md @@ -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(items: T[], callback: Transformer): 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(items: T[], predicate: Transformer): T[] { +``` + +### De fix + +```typescript +type Validator = (value: string) => boolean; +type Transformer = (item: T) => U; +type EventHandler = (event: unknown) => void; + +function transformArray(items: T[], callback: Transformer): 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(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`. + +### 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! diff --git a/Les04-TypeScript-Fundamentals/Les04-Huiswerk-ANTWOORDEN.md b/Les04-TypeScript-Fundamentals/Les04-Huiswerk-ANTWOORDEN.md new file mode 100644 index 0000000..59157ba --- /dev/null +++ b/Les04-TypeScript-Fundamentals/Les04-Huiswerk-ANTWOORDEN.md @@ -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) + * @returns De bijgewerkte User + */ +function updateUser(user: User, updates: Partial): 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 Type**: De `updateUser()` functie accepteert `Partial` 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 = { + 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**: Voor `currencySymbols` gebruiken we `Record` 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; + +/** + * 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` 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>( + 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>( + items: T[], + key: keyof T +): Record { + return items.reduce((groups, item) => { + const value = item[key]; + if (!groups[value]) { + groups[value] = []; + } + groups[value].push(item); + return groups; + }, {} as Record); +} + +export { formatDate, generateId, validateEmail, sortBy, groupBy }; +``` + +### Sleutelbeslissingen bij TypeScript Conversie + +1. **Generieke Type Parameters**: + - `>` 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` + +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` 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 +- `>` 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` constrained het type naar objecten + +### 8. **Typing van Object Methods** +- `Partial` voor optionele updates +- `Record` voor type-safe object literals +- `Pick` en `Omit` 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. diff --git a/Les04-TypeScript-Fundamentals/Les04-Lesplan.md b/Les04-TypeScript-Fundamentals/Les04-Lesplan.md new file mode 100644 index 0000000..5ccacce --- /dev/null +++ b/Les04-TypeScript-Fundamentals/Les04-Lesplan.md @@ -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 = [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` 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.* ✨ diff --git a/Les04-TypeScript-Fundamentals/Les04-Slide-Overzicht.md b/Les04-TypeScript-Fundamentals/Les04-Slide-Overzicht.md new file mode 100644 index 0000000..2db7081 --- /dev/null +++ b/Les04-TypeScript-Fundamentals/Les04-Slide-Overzicht.md @@ -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 +const names: Array = ["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` - 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! + diff --git a/Les04-TypeScript-Fundamentals/les4-huiswerk-js-converter.zip b/Les04-TypeScript-Fundamentals/les4-huiswerk-js-converter.zip new file mode 100644 index 0000000000000000000000000000000000000000..eab9f7fda31ef6e2ae8c3c46e2aa3114025846da GIT binary patch literal 12003 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 literal 0 HcmV?d00001 diff --git a/Les04-TypeScript-Fundamentals/les4-typescript-escaperoom.zip b/Les04-TypeScript-Fundamentals/les4-typescript-escaperoom.zip new file mode 100644 index 0000000000000000000000000000000000000000..9ca8195549906868d88cc9d8d14a30140e765208 GIT binary patch literal 14445 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 Q@bBNgcjaU}{jXpD51Ed`0ssI2 literal 0 HcmV?d00001 diff --git a/Les04-TypeScript-Fundamentals/zi8nE7AW b/Les04-TypeScript-Fundamentals/zi8nE7AW new file mode 100644 index 0000000000000000000000000000000000000000..d8af58811c615d84f5e30c75909e3268cacc5fdf GIT binary patch literal 12891 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 literal 0 HcmV?d00001 diff --git a/Samenvattingen/Les03-Samenvatting.md b/Samenvattingen/Les03-Samenvatting.md index b2b6da4..9893019 100644 --- a/Samenvattingen/Les03-Samenvatting.md +++ b/Samenvattingen/Les03-Samenvatting.md @@ -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 diff --git a/Samenvattingen/Les04-Samenvatting.md b/Samenvattingen/Les04-Samenvatting.md index 3a1b9af..e1b18bc 100644 --- a/Samenvattingen/Les04-Samenvatting.md +++ b/Samenvattingen/Les04-Samenvatting.md @@ -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` +- 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 `) -- 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 diff --git a/readme.md b/readme.md index bb16672..7ba8818 100644 --- a/readme.md +++ b/readme.md @@ -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, Promise) -- 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)