394 lines
7.6 KiB
Markdown
394 lines
7.6 KiB
Markdown
# Les 5: TypeScript Basics
|
|
|
|
---
|
|
|
|
## Hoofdstuk
|
|
**Deel 2: Technical Foundations** (Les 5-9)
|
|
|
|
## Beschrijving
|
|
Introductie tot TypeScript voor React developers. Leer waarom TypeScript waardevol is, hoe je types schrijft, en hoe je het combineert met React.
|
|
|
|
---
|
|
|
|
## Te Behandelen
|
|
|
|
### Waarom TypeScript?
|
|
|
|
**Het probleem met JavaScript:**
|
|
```javascript
|
|
function greet(name) {
|
|
return "Hello, " + name.toUpperCase();
|
|
}
|
|
|
|
greet(42); // Runtime error! 42.toUpperCase is not a function
|
|
```
|
|
|
|
**De oplossing met TypeScript:**
|
|
```typescript
|
|
function greet(name: string): string {
|
|
return "Hello, " + name.toUpperCase();
|
|
}
|
|
|
|
greet(42); // Compile error! Argument of type 'number' is not assignable to type 'string'
|
|
```
|
|
|
|
**Voordelen:**
|
|
- Fouten vinden VOORDAT je code runt
|
|
- Betere autocomplete in je editor
|
|
- Code is zelf-documenterend
|
|
- AI tools begrijpen je code beter
|
|
|
|
---
|
|
|
|
### Basic Types
|
|
|
|
```typescript
|
|
// Primitives
|
|
let name: string = "Tim";
|
|
let age: number = 25;
|
|
let isStudent: boolean = true;
|
|
|
|
// Arrays
|
|
let numbers: number[] = [1, 2, 3];
|
|
let names: string[] = ["Tim", "Anna"];
|
|
|
|
// Alternative array syntax
|
|
let scores: Array<number> = [90, 85, 88];
|
|
|
|
// Objects
|
|
let user: { name: string; age: number } = {
|
|
name: "Tim",
|
|
age: 25
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
### Type Inference
|
|
|
|
TypeScript raadt types vaak zelf:
|
|
|
|
```typescript
|
|
// TypeScript weet dat dit een string is
|
|
let message = "Hello"; // type: string
|
|
|
|
// TypeScript weet dat dit een number is
|
|
let count = 42; // type: number
|
|
|
|
// TypeScript weet wat de functie returned
|
|
function double(x: number) {
|
|
return x * 2; // return type: number (inferred)
|
|
}
|
|
```
|
|
|
|
**Regel:** Je hoeft niet altijd types te schrijven. Laat TypeScript inferren waar mogelijk.
|
|
|
|
---
|
|
|
|
### Interfaces
|
|
|
|
Voor het beschrijven van object shapes:
|
|
|
|
```typescript
|
|
interface User {
|
|
id: number;
|
|
name: string;
|
|
email: string;
|
|
isActive: boolean;
|
|
}
|
|
|
|
const user: User = {
|
|
id: 1,
|
|
name: "Tim",
|
|
email: "tim@example.com",
|
|
isActive: true
|
|
};
|
|
|
|
// Optional properties met ?
|
|
interface Product {
|
|
id: number;
|
|
name: string;
|
|
price: number;
|
|
description?: string; // optioneel
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Type Aliases
|
|
|
|
Alternatief voor interfaces, meer flexibel:
|
|
|
|
```typescript
|
|
// Type alias voor object
|
|
type User = {
|
|
id: number;
|
|
name: string;
|
|
};
|
|
|
|
// Type alias voor union types
|
|
type Status = "pending" | "approved" | "rejected";
|
|
|
|
// Type alias voor functie
|
|
type GreetFunction = (name: string) => string;
|
|
```
|
|
|
|
**Interface vs Type:**
|
|
- Interface: voor objecten, kan extended worden
|
|
- Type: voor alles, meer flexibel
|
|
|
|
---
|
|
|
|
### TypeScript met React
|
|
|
|
**Props typen:**
|
|
|
|
```typescript
|
|
// Interface voor props
|
|
interface ButtonProps {
|
|
label: string;
|
|
onClick: () => void;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
// Component met typed props
|
|
function Button({ label, onClick, disabled = false }: ButtonProps) {
|
|
return (
|
|
<button onClick={onClick} disabled={disabled}>
|
|
{label}
|
|
</button>
|
|
);
|
|
}
|
|
|
|
// Gebruik
|
|
<Button label="Click me" onClick={() => console.log("Clicked!")} />
|
|
```
|
|
|
|
---
|
|
|
|
### useState met Types
|
|
|
|
```typescript
|
|
import { useState } from 'react';
|
|
|
|
// Type inference werkt vaak
|
|
const [count, setCount] = useState(0); // number
|
|
|
|
// Explicit type voor complexe data
|
|
interface User {
|
|
id: number;
|
|
name: string;
|
|
}
|
|
|
|
const [user, setUser] = useState<User | null>(null);
|
|
|
|
// Array van objecten
|
|
const [users, setUsers] = useState<User[]>([]);
|
|
```
|
|
|
|
---
|
|
|
|
### Generics Basics
|
|
|
|
Generics maken code herbruikbaar:
|
|
|
|
```typescript
|
|
// Array is een generic type
|
|
const numbers: Array<number> = [1, 2, 3];
|
|
const names: Array<string> = ["Tim", "Anna"];
|
|
|
|
// Promise is een generic type
|
|
async function fetchUser(): Promise<User> {
|
|
const response = await fetch('/api/user');
|
|
return response.json();
|
|
}
|
|
|
|
// Je kunt ook eigen generics maken
|
|
function firstElement<T>(arr: T[]): T | undefined {
|
|
return arr[0];
|
|
}
|
|
|
|
const first = firstElement([1, 2, 3]); // type: number | undefined
|
|
```
|
|
|
|
---
|
|
|
|
### Veelvoorkomende Errors
|
|
|
|
**Error 1: Type 'X' is not assignable to type 'Y'**
|
|
```typescript
|
|
let name: string = 42; // Error!
|
|
// Fix: gebruik correct type
|
|
let name: string = "Tim";
|
|
```
|
|
|
|
**Error 2: Property 'X' does not exist on type 'Y'**
|
|
```typescript
|
|
interface User { name: string; }
|
|
const user: User = { name: "Tim" };
|
|
console.log(user.age); // Error! 'age' bestaat niet
|
|
// Fix: voeg property toe aan interface
|
|
```
|
|
|
|
**Error 3: Object is possibly 'undefined'**
|
|
```typescript
|
|
const users: User[] = [];
|
|
console.log(users[0].name); // Error! users[0] kan undefined zijn
|
|
// Fix: check eerst
|
|
if (users[0]) {
|
|
console.log(users[0].name);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### JS naar TS Omzetten
|
|
|
|
**Stap 1:** Rename `.js` naar `.tsx` (voor React) of `.ts`
|
|
|
|
**Stap 2:** Fix de rode errors - meestal:
|
|
- Voeg types toe aan function parameters
|
|
- Maak interfaces voor objecten
|
|
- Handle nullable values
|
|
|
|
**Voorbeeld:**
|
|
|
|
```javascript
|
|
// Voorheen (JavaScript)
|
|
function UserCard({ user }) {
|
|
return <div>{user.name}</div>;
|
|
}
|
|
```
|
|
|
|
```typescript
|
|
// Nu (TypeScript)
|
|
interface User {
|
|
id: number;
|
|
name: string;
|
|
}
|
|
|
|
interface UserCardProps {
|
|
user: User;
|
|
}
|
|
|
|
function UserCard({ user }: UserCardProps) {
|
|
return <div>{user.name}</div>;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Tools
|
|
- OpenCode/WebStorm
|
|
- TypeScript (via Next.js)
|
|
- React
|
|
|
|
---
|
|
|
|
## Lesopdracht (2 uur)
|
|
|
|
### TypeScript Hands-on
|
|
|
|
**Deel 1: JS naar TS Omzetten (45 min)**
|
|
|
|
Gegeven JavaScript component:
|
|
|
|
```javascript
|
|
function ProductCard({ product, onAddToCart }) {
|
|
return (
|
|
<div className="p-4 border rounded">
|
|
<h2>{product.name}</h2>
|
|
<p>${product.price}</p>
|
|
{product.description && <p>{product.description}</p>}
|
|
<button onClick={() => onAddToCart(product.id)}>
|
|
Add to Cart
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
Zet dit om naar TypeScript:
|
|
1. Maak `Product` interface
|
|
2. Maak `ProductCardProps` interface
|
|
3. Type de component
|
|
4. Fix alle TypeScript errors
|
|
|
|
**Deel 2: Interfaces Schrijven (30 min)**
|
|
|
|
Maak interfaces voor:
|
|
|
|
1. **User** met: id, name, email, avatar (optioneel), createdAt
|
|
2. **Product** met: id, name, price, description (optioneel), inStock, category
|
|
3. **Order** met: id, userId, products (array), total, status (pending/shipped/delivered)
|
|
|
|
**Deel 3: React Component met Types (45 min)**
|
|
|
|
Bouw een `UserList` component:
|
|
- Props: users array, onSelectUser callback
|
|
- State: selectedUserId (number of null)
|
|
- Toon lijst van users, highlight geselecteerde
|
|
|
|
Alle types moeten correct zijn. Geen `any` gebruiken!
|
|
|
|
### Deliverable
|
|
- ProductCard.tsx met correcte types
|
|
- types.ts met alle interfaces
|
|
- UserList.tsx volledig getypt
|
|
|
|
---
|
|
|
|
## Huiswerk (2 uur)
|
|
|
|
### TypeScript Verdieping
|
|
|
|
**Deel 1: Drie Components Bouwen (1 uur)**
|
|
|
|
Bouw volledig in TypeScript:
|
|
|
|
1. **SearchInput** component
|
|
- Props: value, onChange, placeholder (optioneel)
|
|
- Volledig getypt
|
|
|
|
2. **DataTable** component
|
|
- Generic: werkt met elk type data
|
|
- Props: data array, columns config
|
|
- Type-safe rendering
|
|
|
|
3. **Modal** component
|
|
- Props: isOpen, onClose, title, children
|
|
- Correct gebruik van React.ReactNode
|
|
|
|
**Deel 2: Eindproject Interfaces (30 min)**
|
|
|
|
Bedenk de data structuur voor je eindproject:
|
|
- Welke entiteiten heb je? (users, posts, products, etc.)
|
|
- Maak interface voor elke entiteit
|
|
- Documenteer relaties tussen entiteiten
|
|
|
|
**Deel 3: Cheat Sheet (30 min)**
|
|
|
|
Maak persoonlijke TypeScript cheat sheet:
|
|
- Meest gebruikte types
|
|
- Interface vs Type wanneer
|
|
- Common patterns met React
|
|
- Hoe je errors oplost
|
|
|
|
### Deliverable
|
|
- 3 TypeScript components
|
|
- types/index.ts met eindproject interfaces
|
|
- TypeScript cheat sheet (1 pagina)
|
|
|
|
---
|
|
|
|
## Leerdoelen
|
|
Na deze les kan de student:
|
|
- Uitleggen waarom TypeScript waardevol is
|
|
- Basic types gebruiken (string, number, boolean, arrays)
|
|
- Interfaces en type aliases schrijven
|
|
- React components typen met props
|
|
- useState met types gebruiken
|
|
- Generics op basisniveau begrijpen
|
|
- JavaScript code omzetten naar TypeScript
|
|
- TypeScript errors lezen en oplossen
|