TypeScript is de industriestandaard geworden voor grootschalige webontwikkeling. Hoewel de meeste ontwikkelaars de basisbeginselen van interfaces en types kennen, ligt de echte kracht in het geavanceerde typesysteem. Hier zijn 5 patronen die je als senior engineer onderscheiden.
1. Generic Constraints
Generics zijn krachtig, maar soms moet je beperken wat er kan worden doorgegeven. extends is hier je vriend.
interface HasId { id: string; } function getById<T extends HasId>(list: T[], id: string): T | undefined { return list.find((item) => item.id === id); }
Door ervoor te zorgen dat T HasId uitbreidt, garanderen we dat het benaderen van .id binnen de functie veilig is.
2. Conditional Types
Conditional types stellen je in staat om niet-uniforme type-mappings te creëren. De syntax lijkt op de ternary operator in JavaScript.
type IsString<T> = T extends string ? true : false; type A = IsString<string>; // true type B = IsString<number>; // false
Een praktisch gebruiksscenario is het filteren van types uit een union:
type Diff<T, U> = T extends U ? never : T; type NonNullable<T> = Diff<T, null | undefined>;
3. Mapped Types
Mapped types stellen je in staat om nieuwe types te creëren op basis van bestaande types door eigenschappen te transformeren.
type ReadOnly<T> = { readonly [P in keyof T]: T[P]; }; interface User { name: string; age: number; } type ReadOnlyUser = ReadOnly<User>;
Je kunt zelfs modifiers toevoegen of verwijderen:
type Mutable<T> = { -readonly [P in keyof T]: T[P]; };
4. Template Literal Types
Geïntroduceerd in TypeScript 4.1, hiermee kun je string types direct manipuleren.
type World = 'world'; type Greeting = `hello ${World}`; // "hello world" type Color = 'red' | 'blue'; type Quantity = 'light' | 'dark'; type Palette = `${Quantity}-${Color}`; // "light-red" | "light-blue" | "dark-red" | "dark-blue"
Dit is ontzettend handig voor het typeren van strings die een specifiek patroon volgen, zoals CSS-klassen of eventnamen.
5. Het infer Keyword
Het infer keyword binnen conditional types stelt je in staat om types te extraheren uit andere types.
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any; function check(): boolean { return true; } type CheckReturn = ReturnType<typeof check>; // boolean
Hier vragen we TypeScript om het return type R van een functie te "infereren" en het terug te geven.
Conclusie
Het beheersen van deze patronen stelt je in staat om bibliotheken en hulpprogramma's te schrijven die robuust zijn en een uitstekende ontwikkelaarservaring (DX) bieden. Het doel van geavanceerd TypeScript is niet complexiteit omwille van complexiteit, maar veiligheid en expressiviteit.