Kodokon kodokon.com

Surcharges, this typé et variance

Comprenez la résolution des surcharges, le pseudo-paramètre this et les règles de variance qui gouvernent l'assignabilité des fonctions.

10 min · 3 questions

Ouvrir cette leçon dans Kodokon

Une fonction surchargée expose une liste de signatures publiques suivies d'une unique signature d'implémentation. Point de spécification essentiel : cette dernière est invisible de l'extérieur ; seules les surcharges déclarées sont appelables. La résolution parcourt les signatures de haut en bas et retient la première compatible : placez donc toujours la plus spécifique en premier, sinon elle ne sera jamais sélectionnée.

TYPESCRIPT
function parse(input: string): number;
function parse(input: string[]): number[];
function parse(input: string | string[]) {
  return Array.isArray(input)
    ? input.map((s) => s.length)
    : input.length;
}

const single = parse("abc");      // number
const many = parse(["a", "bb"]);  // number[]
Chaque appel résout vers une surcharge précise.

TypeScript permet de déclarer un pseudo-paramètre this en première position. Il est entièrement effacé du JavaScript émis : c'est une contrainte purement statique sur le contexte d'appel, vérifiée quand noImplicitThis est actif. Les utilitaires ThisParameterType et OmitThisParameter permettent de l'extraire ou de le retirer, ce qui est indispensable pour typer des fonctions destinées à call, apply ou bind.

TYPESCRIPT
function greet(this: { name: string }, msg: string) {
  return `${msg}, ${this.name}`;
}

type Ctx = ThisParameterType<typeof greet>;
// { name: string }
type Fn = OmitThisParameter<typeof greet>;
// (msg: string) => string

const user = { name: "Ada", greet };
user.greet("Bonjour"); // "Bonjour, Ada"

// greet("Salut"); // erreur : contexte this absent
Le paramètre this contraint le site d'appel, pas le JS émis.

La variance décrit comment l'assignabilité se propage à travers un constructeur de types. Pour les fonctions, les types de retour sont covariants et, avec strictFunctionTypes, les paramètres sont contravariants : une fonction acceptant plus large peut remplacer une fonction acceptant plus étroit, jamais l'inverse. Exception délibérée : les paramètres des méthodes déclarées en syntaxe raccourcie restent bivariants, un compromis historique sans lequel Array<Dog> ne serait pas assignable à Array<Animal>. Depuis la 4.7, vous pouvez annoter la variance attendue avec in et out, par exemple interface Producer<out T>, et le compilateur la vérifie.

TYPESCRIPT
interface Animal { name: string }
interface Dog extends Animal { bark(): void }

declare let f: (a: Dog) => void;
declare let g: (a: Animal) => void;

f = g; // OK : g accepte plus large, c'est sur
// g = f; // erreur avec strictFunctionTypes

interface Sink { accept(a: Animal): void }
interface DogSink { accept(a: Dog): void }
declare let s: Sink;
declare let d: DogSink;

d = s; s = d; // les deux passent : bivariance !
Propriétés fonction strictes, méthodes bivariantes.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Lors d'un appel à une fonction surchargée, quelle signature le compilateur retient-il ?
    • La signature la plus générale
    • La première signature compatible dans l'ordre de déclaration
    • La signature d'implémentation
    • L'union de toutes les signatures
  2. Que devient le paramètre this d'une fonction dans le JavaScript émis ?
    • Il devient un premier argument réel
    • Il disparaît : c'est une annotation purement statique
    • Il est remplacé par un appel à bind
    • Il provoque une erreur à l'exécution s'il manque
  3. Avec strictFunctionTypes, quelle syntaxe bénéficie d'une vérification contravariante stricte des paramètres ?
    • Les méthodes en syntaxe raccourcie, comme m(a: X): void
    • Les propriétés de type fonction, comme m: (a: X) => void
    • Les deux syntaxes
    • Aucune des deux