Nouveau : Datasets open source gratuits disponibles !Decouvrir →
🔷
Avance 20 min TypeScript

Utility Types en TypeScript

Pourquoi Utility Types en TypeScript ?

Utility Types sont une fonctionnalité puissante et flexible de TypeScript qui permettent aux développeurs de créer des types personnalisés à partir d'autres types existants. Ils offrent une grande facilité pour transformer, étendre ou modifier des types sans réinventer la roue.

Un cas concret d'utilisation est le type Partial<T>, qui transforme toutes les propriétés d'un type en optionnelles. Cela peut être très utile lors de l'update d'un objet partiellement, où vous n'avez pas besoin de spécifier toutes les propriétés.

Prerequis

  • Connaissance avancée de TypeScript (10+ ans d'expérience)
  • Familiarité avec le système de types et des interfaces en TypeScript

Outils à installer :

  • Node.js (v14.0+)
  • npm (v6.0+)

Concepts fondamentaux

1. Partial<T>

Partial<T> permet de rendre toutes les propriétés d'un type optionnelles.

interface User {
    id: number;
    name: string;
    email: string;
}

type PartialUser = Partial<User>; // { id?: number; name?: string; email?: string }

2. Required<T>

Required<T> inverse la propriété de Partial<T>, rendant toutes les propriétés obligatoires.

type RequiredUser = Required<PartialUser>; // { id: number; name: string; email: string }

3. Readonly<T>

Readonly<T> rend toutes les propriétés du type en lecture seule, empêchant leur modification.

const user: Readonly<User> = {
    id: 1,
    name: "John",
    email: "john@example.com"
};

// Error: Cannot assign to 'id' because it is a read-only property.
// user.id = 2;

4. Pick<T, K>

Pick<T, K> permet de sélectionner un sous-ensemble des propriétés d'un type.

type UserName = Pick<User, "name">; // { name: string }

5. Omit<T, K>

Omit<T, K> permet de supprimer une ou plusieurs propriétés d'un type.

type UserWithoutId = Omit<User, "id">; // { name: string; email: string }

6. Record<K, T>

Record<K, T> crée un nouveau type en utilisant les clés de K et les valeurs de T.

type UserMap = Record<string, User>; // { [key: string]: { id: number; name: string; email: string } }

7. Exclude<T, U>

Exclude<T, U> permet d'exclure des types à partir d'un type.

type NonNumericKeys = Exclude<keyof User, "id">; // "name" | "email"

8. Extract<T, U>

Extract<T, U> permet de filtrer les types qui correspondent à un modèle donné.

type NumericKeys = Extract<keyof User, number>; // never

Mise en pratique : projet fil rouge

Nous allons construire une API simple pour gérer des utilisateurs. L'API devra être capable d'ajouter, de mettre à jour et de supprimer des utilisateurs.

Étape 1 : Définition du type User et création de l'interface IUserService

// user.ts

export interface User {
    id: number;
    name: string;
    email: string;
}

export interface IUserService {
    addUser(user: User): void;
    updateUser(id: number, updatedUser: Partial<User>): void;
    deleteUser(id: number): void;
}

Étape 2 : Création de la classe UserService implémentant l'interface

// userService.ts

import { User } from './user';

export class UserService implements IUserService {
    private users: User[] = [];

    addUser(user: User): void {
        this.users.push({ ...user, id: Date.now() });
    }

    updateUser(id: number, updatedUser: Partial<User>): void {
        const userIndex = this.users.findIndex(u => u.id === id);
        if (userIndex !== -1) {
            this.users[userIndex] = { ...this.users[userIndex], ...updatedUser };
        }
    }

    deleteUser(id: number): void {
        this.users = this.users.filter(u => u.id !== id);
    }
}

Étape 3 : Création du fichier app.ts pour tester l'API

// app.ts

import { IUserService, UserService } from './userService';
import { User } from './user';

const userService: IUserService = new UserService();

// Ajout d'un utilisateur
userService.addUser({ name: "John", email: "john@example.com" });
console.log("Users after adding:", userService.users);

// Mise à jour d'un utilisateur
userService.updateUser(userService.users[0].id, { name: "Johnny" });
console.log("Users after updating:", userService.users);

// Suppression d'un utilisateur
userService.deleteUser(userService.users[0].id);
console.log("Users after deleting:", userService.users);

Étape 4 : Exécution du code

npm install -g typescript
## 
tsc app.ts && node app.js

Erreurs frequentes et debugging

Erreur 1: Typer le type Partial<User> incorrectement

// ❌ Mauvais
const partialUser = { name: "John" } as Partial<User>; // Ne fonctionne pas si User a d'autres propriétés non optionnelles

Correction :

// ✅ Correct
const partialUser: Partial<User> = { name: "John" };

Erreur 2: Méthode updateUser incorrectement utilisée

// ❌ Mauvais
userService.updateUser(userService.users[0].id, { id: 1 }); // Remplace le user par un nouveau avec l'id spécifié

Correction :

// ✅ Correct
userService.updateUser(userService.users[0].id, { name: "Johnny" });

Erreur 3: Suppression de l'utilisateur incorrectement utilisée

// ❌ Mauvais
userService.deleteUser(1); // Id n'existe pas, supprime le premier utilisateur si id est inexistant

Correction :

// ✅ Correct
const userToDelete = userService.users.find(u => u.id === 1);
if (userToDelete) {
    userService.deleteUser(userToDelete.id);
}

Pour aller plus loin

1. Types génériques avancés

Enfoncez votre compréhension des types génériques en essayant de créer vos propres utility types complexes.

2. Interface vs Type alias

Explorez la différence entre les interfaces et les type aliases, et quand utiliser chaque un. Cette compréhension vous aidera à choisir le bon type pour chaque situation.

3. Types avancés avec infer

infer est une fonctionnalité puissante permettant de déduire des types à partir d'autres types. Apprenez à l'utiliser pour créer des utility types très sophistiqués.

Défi pratique

Créez un type utility DeepReadonly<T> qui rend toutes les propriétés, y compris celles imbriquées, en lecture seule. Utilisez le type keyof et la récursivité pour implémenter cela.

Besoin d'aide sur TypeScript ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.