TypeScript Tips die Elke Developer Zou Moeten Kennen

Praktische TypeScript tips en tricks om je code robuuster, leesbaarder en makkelijker te onderhouden te maken.

Jean-Pierre Broeders

Freelance DevOps Engineer

18 februari 20264 min. leestijd
TypeScript Tips die Elke Developer Zou Moeten Kennen

TypeScript Tips die Elke Developer Zou Moeten Kennen

TypeScript is inmiddels de standaard geworden in veel projecten — en terecht. Maar de taal heeft meer in huis dan alleen string en number. In dit artikel deel ik concrete tips die je dag-tot-dag TypeScript werk een stuk aangenamer maken.

1. Gebruik satisfies in Plaats van Type Assertions

Vanaf TypeScript 4.9 heb je de satisfies operator. Die geeft je het beste van twee werelden: type-checking én automatisch type-inference.

const config = {
  port: 3000,
  host: "localhost",
  debug: true,
} satisfies Record<string, string | number | boolean>;

// TypeScript weet nu dat config.port een number is — niet string | number | boolean
console.log(config.port.toFixed(0)); // ✅ werkt

Met een gewone type annotatie (: Record<string, ...>) zou je config.port als union type zien en verlies je de specifieke inferentie.

2. Template Literal Types voor Veilige String Patronen

Je kunt string patronen nu sterk typeren:

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type ApiRoute = `/api/${string}`;
type Endpoint = `${HttpMethod} ${ApiRoute}`;

function callApi(endpoint: Endpoint): Promise<Response> {
  const [method, url] = endpoint.split(" ", 2);
  return fetch(url, { method });
}

callApi("GET /api/users");       // ✅
callApi("PATCH /api/users");     // ❌ Type error
callApi("GET users");            // ❌ Type error

Dit vangt fouten op compile-time op die anders pas in productie opduiken.

3. Discriminated Unions: Betere Error Handling

Stop met any als return type bij functies die kunnen falen. Gebruik een discriminated union:

type Result<T> =
  | { success: true; data: T }
  | { success: false; error: string };

async function fetchUser(id: string): Promise<Result<User>> {
  try {
    const user = await db.users.findById(id);
    if (!user) return { success: false, error: "Gebruiker niet gevonden" };
    return { success: true, data: user };
  } catch (e) {
    return { success: false, error: "Database fout" };
  }
}

// Gebruik:
const result = await fetchUser("123");
if (result.success) {
  console.log(result.data.name); // TypeScript weet dat data hier bestaat
} else {
  console.error(result.error);   // En dat error hier bestaat
}

4. const Assertions voor Onveranderlijke Data

Wil je dat een object of array volledig als readonly en literal type wordt behandeld?

const STATUSES = ["pending", "active", "archived"] as const;
type Status = typeof STATUSES[number]; // "pending" | "active" | "archived"

const DEFAULT_CONFIG = {
  retries: 3,
  timeout: 5000,
  strategy: "exponential",
} as const;

Zonder as const zou Status gewoon string zijn. Met as const krijg je exacte literal types — en je kunt de array nooit per ongeluk muteren.

5. Utility Types Slim Inzetten

TypeScript heeft een rijke standaardbibliotheek van utility types. Gebruik ze:

interface User {
  id: string;
  name: string;
  email: string;
  role: "admin" | "user";
  createdAt: Date;
}

// Alleen bepaalde velden verplicht bij aanmaken
type CreateUserDto = Pick<User, "name" | "email" | "role">;

// Alles optioneel voor updates
type UpdateUserDto = Partial<Pick<User, "name" | "email">>;

// Alles readonly voor view-only contexts
type UserView = Readonly<User>;

// Zonder gevoelige velden
type PublicUser = Omit<User, "email" | "role">;

Dit bespaart je een hoop dubbele type-definities.

6. Generics met Constraints

Generics worden pas echt krachtig als je constraints toevoegt:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: "JP", age: 30, active: true };
const name = getProperty(user, "name");   // type: string ✅
const age  = getProperty(user, "age");    // type: number ✅
getProperty(user, "missing");             // ❌ compile error

7. Type Guards voor Runtime Veiligheid

TypeScript types bestaan alleen op compile-time. Als je data van buiten verwerkt (API, JSON), heb je runtime checks nodig:

interface ApiUser {
  id: string;
  name: string;
  email: string;
}

function isApiUser(data: unknown): data is ApiUser {
  return (
    typeof data === "object" &&
    data !== null &&
    typeof (data as ApiUser).id === "string" &&
    typeof (data as ApiUser).name === "string" &&
    typeof (data as ApiUser).email === "string"
  );
}

const raw = await response.json();
if (isApiUser(raw)) {
  console.log(raw.name); // ✅ TypeScript vertrouwt het nu
}

Conclusie

TypeScript is meer dan een type-checker op JavaScript. Met satisfies, discriminated unions, template literal types en slimme utility types schrijf je code die minder bugs bevat en makkelijker te lezen en refactoren is. Begin met één tip die je nog niet gebruikte en bouw van daar verder.

Goede TypeScript is geen kunst — het is een gewoonte.

Wil je op de hoogte blijven?

Schrijf je in voor mijn nieuwsbrief of neem contact op voor freelance projecten.

Neem Contact Op