TW3 — Technologies du Web 3

Utility types et type guards

Transformer des types existants avec Partial/Pick/Omit/Record, valider des données inconnues avec les type guards (v is T), et découvrir satisfies.

Quand les besoins grandissent, on ne réécrit pas les variantes à la main : on les dérive des types existants.

🛠️ Utility types

Un utility type est un type utilitaire qui transforme un type existant pour en créer une variante. Partial, Pick, Omit, Record sont des utility types built-in de TypeScript.

Partial<T> rend toutes les propriétés de T optionnelles. Utile pour les mises à jour partielles (PATCH).

Pick<T, K> extrait uniquement les propriétés K de T. Utile pour créer une vue légère d'un objet.

Omit<T, K> retire les propriétés K de T. Utile pour exclure un champ (comme password).

Record<K, V> crée un type objet dont les clés sont de type K et les valeurs de type V. C'est un dictionnaire typé.

UtilitaireEffetCas d'usage
Partial<T>toutes les clés optionnellesmise à jour partielle
Pick<T, K>ne garde que les clés Kvue légère
Omit<T, K>retire les clés Kexclure un champ
Record<K, V>clés K pointant vers Vdictionnaire
interface User {
  id: number
  nom: string
  email: string
}

type UserPatch = Partial<User>
type UserLight = Pick<User, "id" | "nom">
type UserSansEmail = Omit<User, "email">
type UsersById = Record<number, User>

Un type dérivé est un type construit à partir d'un autre type existant. Les utility types produisent des types dérivés. Un changement dans le type source se propage automatiquement aux types dérivés.

✅ satisfies

satisfies est un opérateur qui vérifie qu'une valeur respecte un type sans élargir son type inféré. Contrairement à l'annotation : Type, satisfies conserve le type précis de la valeur.

satisfies vérifie qu'une valeur respecte un type sans élargir le type inféré :

const config = {
  production: true,
  port: 3000,
} satisfies Record<string, boolean | number>

config.production   // typé boolean (pas boolean | number)
config.port         // typé number

🛡️ Type guards

Un type guard (garde de type) est une fonction qui retourne un prédicat v is T. Elle affirme au compilateur que si elle retourne true, alors v est de type T. Le narrowing s'applique dans la branche if.

Un prédicat de type est la syntaxe v is T dans le type de retour d'une fonction. C'est ce qui distingue une type guard d'un simple retour boolean.

Une fonction qui restreint un type via is :

interface User {
  id: number
  nom: string
  email: string
}

function estUser(v: unknown): v is User {
  return (
    typeof v === "object" &&
    v !== null &&
    "id" in v &&
    typeof (v as User).id === "number" &&
    "nom" in v &&
    typeof (v as User).nom === "string" &&
    "email" in v &&
    typeof (v as User).email === "string"
  )
}

declare const data: unknown

if (estUser(data)) {
  console.log(data.id)   // data est User ici
} else {
  console.log("Format invalide")
}

Utilisez unknown (sûr) et non any (dangereux) dans les type guards. any désactive toute vérification.

import type importe uniquement la déclaration d'un type, sans code au runtime. Le type est éliminé lors du build (tree-shaking).

🔑 keyof et typeof

keyof est un opérateur qui extrait les clés d'un type sous forme d'un union. keyof User donne "id" | "nom" | "email". Utile pour typer des fonctions qui accèdent à une propriété dynamiquement.

interface User {
  id: number
  nom: string
  email: string
}

type ClesUser = keyof User // "id" | "nom" | "email"

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

const user: User = { id: 1, nom: "Alice", email: "alice@exemple.fr" }
const nom = getProperty(user, "nom") // string
const id = getProperty(user, "id")   // number

typeof (en contexte de type) extrait le type d'une valeur existante. typeof maVariable dans une annotation de type donne le type de maVariable. Utile pour typer à partir d'une constante sans la retaper.

const utilisateur = {
  id: 1,
  nom: "Alice",
  email: "alice@exemple.fr",
}

type User = typeof utilisateur
// { id: number; nom: string; email: string }

🗺️ Mapped types

Un mapped type est un type qui transforme les propriétés d'un type existant via une boucle sur ses clés. Syntaxe { [K in keyof T]: ... }. Les utility types (Partial, Pick…) sont des mapped types built-in.

Créer un type où toutes les propriétés deviennent optionnelles (équivalent de Partial) :

type MonPartial<T> = {
  [K in keyof T]?: T[K]
}

Créer un type où toutes les propriétés deviennent readonly :

type MonReadonly<T> = {
  readonly [K in keyof T]: T[K]
}

Transformer les types des valeurs :

type Stringify<T> = {
  [K in keyof T]: string
}

interface User {
  id: number
  nom: string
  age: number
}

type UserString = Stringify<User>
// { id: string; nom: string; age: string }

Combiner avec les template literal types :

type User = {
  id: number
  nom: string
}

type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}

type UserGetters = Getters<User>
// { getId: () => number; getNom: () => string }

📋 Points clés

  • Utility type : transforme un type existant (Partial, Pick, Omit, Record).
  • Type dérivé : construit à partir d'un autre type, se propage automatiquement.
  • satisfies : valide sans élargir le type inféré.
  • Type guard (v is T) : fonction qui prouve un type via un prédicat.
  • Prédicat : syntaxe v is T qui permet le narrowing.
  • import type : import de type uniquement, éliminé au build.
  • keyof : extrait les clés d'un type sous forme d'union.
  • typeof (type) : extrait le type d'une valeur existante.
  • Mapped type : transforme les propriétés via { [K in keyof T]: ... }.

✅ Vérification des acquis

Quiz du chapitre

3 questions
0 / 3 répondue0%
  1. 1Que produit Partial<User> ?
  2. 2Que permet une fonction 'v is User' ?
  3. 3Quelle différence entre 'satisfies' et une annotation de type ?
Répondez à toutes les questions pour valider.

TypeScript

Terminez le quiz du chapitre pour le marquer comme complété.

Tableau de bord

On this page