Publie le 24 mars 2026 Par

TypeScript generics : comprendre et utiliser les types génériques

Les generics TypeScript sont le concept qui fait passer d’un TypeScript « fonctionnel » à un TypeScript vraiment typé. Beaucoup de développeurs les évitent ou copient des patterns sans les comprendre. Ce guide les démystifie avec des exemples concrets — pas des exemples académiques déconnectés de la réalité.

Pourquoi les generics existent

Sans generics, vous avez deux options mauvaises : any (perd tout typage) ou dupliquer le code pour chaque type. Les generics permettent d’écrire du code réutilisable qui conserve l’information de type.

// Sans generics — on duplique ou on perd le type
function firstElement(arr: number[]): number { return arr[0] }
function firstElementStr(arr: string[]): string { return arr[0] }

// Avec generics — une seule fonction, type préservé
function firstElement(arr: T[]): T {
  return arr[0]
}

const num = firstElement([1, 2, 3])     // TypeScript sait que num: number
const str = firstElement(['a', 'b'])    // TypeScript sait que str: string

La syntaxe de base

// T est une convention — vous pouvez utiliser n'importe quel nom
// T = Type, K = Key, V = Value, E = Element sont les conventions courantes

// Fonction générique
function identity(value: T): T {
  return value
}

// Interface générique
interface ApiResponse {
  data: T
  status: number
  message: string
}

// Type générique
type Nullable = T | null
type Optional = T | undefined

// Utilisation
const response: ApiResponse = await fetchUsers()
const maybeUser: Nullable = getUser(id)

Les contraintes — extends

Parfois, vous avez besoin que le type générique ait certaines propriétés. extends permet de contraindre T :

// T doit avoir une propriété id
function getById(items: T[], id: string): T | undefined {
  return items.find(item => item.id === id)
}

// Fonctionne avec n'importe quel objet qui a un id
getById(users, '123')    // ✅ User a un id
getById(products, '456') // ✅ Product a un id
getById([1, 2, 3], '1') // ❌ number n'a pas de id

// Contrainte avec keyof — accéder à une propriété de façon type-safe
function getProperty(obj: T, key: K): T[K] {
  return obj[key]
}

const user = { name: 'Alice', age: 30 }
getProperty(user, 'name') // string — type inféré correctement
getProperty(user, 'age')  // number
getProperty(user, 'xyz')  // ❌ Erreur de compilation — 'xyz' n'est pas une clé de user

Les generics en React

Les generics sont très utiles pour typer correctement les composants et hooks React :

// Hook générique pour fetcher des données
function useFetch(url: string) {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  useEffect(() => {
    fetch(url)
      .then(r => r.json())
      .then((d: T) => setData(d))
      .catch(setError)
      .finally(() => setLoading(false))
  }, [url])

  return { data, loading, error }
}

// Usage avec le type inféré
const { data: users } = useFetch('/api/users')
// users est typé User[] | null — pas any

// Composant générique pour liste
interface ListProps {
  items: T[]
  renderItem: (item: T) => React.ReactNode
  keyExtractor: (item: T) => string
}

function List({ items, renderItem, keyExtractor }: ListProps) {
  return (
    
    {items.map(item => (
  • {renderItem(item)}
  • ))}
) } // Usage {user.name}} keyExtractor={user => user.id} />

Les utility types — les generics déjà fournis

TypeScript fournit des types utilitaires génériques prêts à l’emploi. Ce sont les plus utilisés en pratique :

interface User {
  id: string
  name: string
  email: string
  role: 'admin' | 'user'
}

// Partial — toutes les propriétés deviennent optionnelles
type UserUpdate = Partial
// { id?: string; name?: string; email?: string; role?: ... }

// Required — toutes les propriétés deviennent requises
type RequiredUser = Required>

// Pick — sélectionner des propriétés
type UserPreview = Pick
// { id: string; name: string }

// Omit — exclure des propriétés
type UserWithoutId = Omit
// { name: string; email: string; role: ... }

// Record — créer un type objet avec clés et valeurs typés
type RolePermissions = Record<'admin' | 'user', string[]>

// ReturnType — extraire le type de retour d'une fonction
type FetchResult = ReturnType

// Parameters — extraire les paramètres d'une fonction
type FetchParams = Parameters

L’erreur la plus courante

Ne pas inférer le type quand TypeScript peut le faire seul :

// ❌ Redondant — TypeScript infère T = string depuis l'argument
const result = identity('hello')

// ✅ TypeScript infère T automatiquement
const result = identity('hello') // T = string, inféré

// ❌ Trop de generics — si vous en avez 4+, c'est souvent un signe de sur-ingénierie
function doThing(a: A, b: B): C { ... }

// ✅ Simplifier avec des types plus spécifiques si possible

Offres TypeScript et React

Des postes pour développeurs TypeScript — les équipes qui codent avec des types stricts et qui vous feront progresser.

À lire aussi : TypeScript pour développeurs JSHooks ReactReact vs Vue vs Angular

Categories : JavaScript & React