Surcharges de fonction

Plusieurs signatures pour une seule fonction : le type du résultat dépend des arguments avec lesquels vous l’appelez.

Sur cette page

Exemple

#
TypeScript
function toPoints(value: string): number
function toPoints(values: string[]): number[]
function toPoints(input: string | string[]): number | number[] {
  if (Array.isArray(input)) return input.map((item) => Number.parseInt(item, 10))
  return Number.parseInt(input, 10)
}

const single = toPoints('120')
// const single: number
const many = toPoints(['40', '75', '90'])
// const many: number[]

console.log(single + 30)
console.log(many)
Résultat
150
[40, 75, 90]

Définition et utilisation

#

Les surcharges décrivent une fonction unique avec plusieurs signatures. Vous écrivez d’abord les en-têtes seuls, sans corps, puis juste en dessous une seule implémentation. Lors de l’appel, le compilateur examine les en-têtes de haut en bas et choisit le premier qui correspond aux arguments. Ainsi, pour une chaîne, la fonction peut renvoyer un nombre, et pour un tableau de chaînes, un tableau de nombres.

La signature de l’implémentation est cachée : seules les surcharges sont visibles depuis l’extérieur. L’implémentation doit gérer toutes les variantes, donc elle accepte généralement une union de types et la restreint elle-même à l’intérieur, par exemple avec Array.isArray() ou typeof. Si un en-tête ne lui correspond pas, le compilateur signale « This overload signature is not compatible with its implementation signature ».

Vous pouvez aussi surcharger des méthodes de classes, et dans les interfaces, il suffit d’écrire plusieurs signatures d’appel. Mais avant de recourir aux surcharges, vérifiez si une union, un paramètre optionnel ou un générique ne suffirait pas. Les surcharges sont utiles quand le type du résultat dépend des arguments, ou quand les variantes diffèrent par le nombre et le sens de leurs paramètres.

Syntaxe

#
Syntaxe
function name(a: TypeA): ResultA
function name(a: TypeB): ResultB
function name(a: TypeA | TypeB): ResultA | ResultB {
  // implémentation
}

Plus d’exemples

#
Un nombre d’arguments différent
TypeScript
function makeRange(end: number): number[]
function makeRange(start: number, end: number): number[]
function makeRange(a: number, b?: number): number[] {
  const [start, end] = b === undefined ? [0, a] : [a, b]
  return Array.from({ length: end - start }, (_, i) => start + i)
}

console.log(makeRange(4))
console.log(makeRange(2, 5))

makeRange(1, 2, 3)
// Erreur : Expected 1-2 arguments, but got 3.
Résultat
[0, 1, 2, 3]
[2, 3, 4]
Un appel qui ne correspond à aucune signature
TypeScript
toPoints(42)
// Erreur : No overload matches this call.
//   Overload 1 of 2, '(value: string): number', gave the following error.
//     Argument of type 'number' is not assignable to parameter of type 'string'.
//   Overload 2 of 2, '(values: string[]): number[]', gave the following error.
//     Argument of type 'number' is not assignable to parameter of type 'string[]'.

Bonnes pratiques

#
  • Classez les surcharges de la plus spécifique à la plus générale. Le compilateur prend la première qui correspond, donc une signature générale placée en haut masquerait les autres.
  • Un argument de type union, par exemple string | string[], ne correspond à aucune des surcharges de l’exemple, car la signature de l’implémentation n’est pas visible. Si de tels appels sont nécessaires, ajoutez une surcharge séparée qui accepte l’union.
  • Quand toutes les variantes renvoient le même type et ne diffèrent que par le type du paramètre, remplacez les surcharges par une seule signature avec une union. Le code sera plus court, et les suggestions de l’éditeur plus simples.

Entrées associées

#

Vous voyez une erreur ou il manque un exemple ? Écrivez-nous.