Geavanceerde TypeScript-typen uitgelegd met voorbeelden

TypeScript biedt verschillende geavanceerde typen die verder gaan dan basistypen, wat flexibelere en krachtigere typesystemen mogelijk maakt. Deze geavanceerde typen helpen bij het maken van robuuste toepassingen door extra manieren te bieden om typebeperkingen te definiëren en af ​​te dwingen. Dit artikel onderzoekt enkele van deze geavanceerde typen met voorbeelden.

Unie-typen

Union-typen maken het mogelijk dat een variabele een van meerdere typen is. Dit kan handig zijn wanneer een waarde van meerdere typen kan zijn, maar op de juiste manier moet worden behandeld op basis van het werkelijke type.

// Union type example

function formatValue(value: string | number): string {
  if (typeof value === 'string') {
    return `String: ${value}`;
  } else {
    return `Number: ${value.toFixed(2)}`;
  }
}

console.log(formatValue("Hello"));
console.log(formatValue(123.456));

In dit voorbeeld accepteert de functie `formatValue` een tekenreeks of een getal en formatteert de waarde dienovereenkomstig.

Kruispunttypen

Intersection-typen combineren meerdere typen tot één. Een object van een intersection-type heeft alle eigenschappen van de gecombineerde typen. Dit is handig voor het samenstellen van meerdere typen.

// Intersection type example

interface Person {
  name: string;
  age: number;
}

interface Contact {
  email: string;
  phone: string;
}

type Employee = Person & Contact;

const employee: Employee = {
  name: "John Doe",
  age: 30,
  email: "john.doe@example.com",
  phone: "123-456-7890"
};

console.log(employee);

Het type `Werknemer` is hier een kruispunt van `Persoon` en `Contactpersoon`, wat betekent dat het eigenschappen van beide interfaces bevat.

Letterlijke typen

Letterlijke typen specificeren exacte waarden die een variabele kan bevatten. Dit kan met name handig zijn om ervoor te zorgen dat alleen bepaalde specifieke waarden zijn toegestaan.

// Literal type example

type Direction = "up" | "down" | "left" | "right";

function move(direction: Direction): void {
  console.log(`Moving ${direction}`);
}

move("up");    // Valid
move("down");  // Valid
// move("side"); // Error: Argument of type '"side"' is not assignable to parameter of type 'Direction'.

Het type `Direction` is hier beperkt tot vier specifieke tekenreekswaarden, zodat alleen deze richtingen kunnen worden gebruikt in de `move`-functie.

Tuple-typen

Tuple-typen vertegenwoordigen een array met een vast aantal elementen waarbij elk element een ander type kan hebben. Tuples zijn handig voor het vertegenwoordigen van vaste-grootte verzamelingen van heterogene items.

// Tuple type example

let user: [string, number] = ["Alice", 30];

console.log(user[0]); // "Alice"
console.log(user[1]); // 30

// user = [30, "Alice"]; // Error: Type 'number' is not assignable to type 'string'.

Het `user`-tupel wordt gedefinieerd met een tekenreeks gevolgd door een getal. Deze structuur moet behouden blijven.

Voorwaardelijke typen

Met conditionele typen kunnen typen worden bepaald op basis van voorwaarden. Ze bieden een manier om het ene of het andere type te selecteren op basis van een voorwaarde.

// Conditional type example

type IsString = T extends string ? "Yes" : "No";

type Test1 = IsString;  // "Yes"
type Test2 = IsString;  // "No"

In dit voorbeeld controleert het type `IsString` of een type `T` een string is. Het retourneert `"Yes"` als dat zo is en `"No"` anders.

In kaart gebrachte typen

Mapped types maken het mogelijk om nieuwe types te creëren door eigenschappen van een bestaand type te transformeren. Dit is handig voor het aanpassen of uitbreiden van bestaande types.

// Mapped type example

type ReadonlyPerson = {
  readonly [K in keyof Person]: Person[K];
};

const readonlyPerson: ReadonlyPerson = {
  name: "Alice",
  age: 30
};

// readonlyPerson.age = 31; // Error: Cannot assign to 'age' because it is a read-only property.

Het type `ReadonlyPerson` transformeert het type `Person` door alle eigenschappen alleen-lezen te maken.

Conclusie

De geavanceerde typen van TypeScript bieden krachtige tools voor het definiëren en beheren van complexe typevereisten. Door gebruik te maken van union, intersection, literal, tuple, conditional en mapped typen, kunnen ontwikkelaars robuustere en onderhoudbare applicaties maken. Het begrijpen en effectief toepassen van deze typen kan de typeveiligheid en flexibiliteit van TypeScript-code aanzienlijk verbeteren.