En TypeScript, un constructeur est la méthode constructor de la classe, avec des paramètres typés. Il n'a pas d'annotation de type de retour : il produit toujours une instance de la classe.
Écrire constructor(): Product provoque l'erreur TS1093 (Type annotation cannot appear on a constructor declaration). Tout le reste du fonctionnement de new est du JavaScript pur.
Propriétés de paramètres
Le motif ci-dessus (déclarer un champ, prendre un paramètre, le recopier) est si courant que TypeScript propose un raccourci. Placez public, private, protected ou readonly devant un paramètre du constructeur et il devient un champ :
C'est l'une des rares fonctionnalités de TypeScript qui génèrent du code. Le compilateur écrit les assignations pour vous :
class Product {
name;
price;
sku;
constructor(name, price, sku) {
this.name = name;
this.price = price;
this.sku = sku;
}
// ...
}
Comme il ne s'agit pas seulement de types effacés, les propriétés de paramètres ne fonctionnent pas avec le type stripping intégré de Node (node file.ts échoue avec ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX), et l'option de compilation erasableSyntaxOnly les signale par l'erreur TS1294. Les projets qui exécutent directement des fichiers .ts écrivent les champs à la main.
Paramètres optionnels et par défaut
Les paramètres du constructeur suivent les mêmes règles que ceux des fonctions : ? en rend un optionnel, une valeur par défaut le rend optionnel et le remplit, et les paramètres obligatoires viennent en premier.
Les propriétés de paramètres peuvent aussi avoir des valeurs par défaut. Le type de color dans la classe est string | undefined : le code qui l'utilise doit donc d'abord vérifier undefined.
Pour les constructeurs à nombreuses options, un seul objet d'options se lit mieux qu'une longue liste positionnelle : constructor(opts: { prefix: string; level?: "info" | "debug" }).
Ordre d'initialisation des champs
Les initialiseurs de champs s'exécutent avant le corps du constructeur, et les propriétés de paramètres sont assignées au début du corps du constructeur. Un initialiseur de champ ne peut donc pas lire une propriété de paramètre. TypeScript le détecte :
index.ts(3,18): error TS2729: Property 'size' is used before its initialization.
index.ts(3,30): error TS2729: Property 'size' is used before its initialization.
À l'exécution, l'initialiseur verrait undefined et produirait NaN. Calculez plutôt la valeur dans le corps du constructeur :
class Grid {
cells: number;
constructor(public size: number) {
this.cells = size * size;
}
}
console.log(new Grid(3).cells); // 9
Surcharges de constructeur
Une classe a exactement une implémentation de constructeur, mais vous pouvez lister plusieurs signatures de surcharge au-dessus. Les appelants ne voient que les surcharges ; la signature d'implémentation doit être compatible avec toutes.
Les surcharges deviennent difficiles à lire au-delà de deux ou trois formes. Des méthodes de fabrique statiques aux noms explicites (Color.fromHex("#ff8800"), Color.fromRgb(10, 20, 30)) sont souvent plus claires et ne demandent aucun narrowing dans un corps unique.
Appeler super dans une sous-classe
Une classe dérivée qui déclare son propre constructeur doit appeler super(...) avec les arguments du parent, et doit le faire avant de toucher à this. Oublier l'appel provoque l'erreur TS2377 (Constructors for derived classes must contain a 'super' call), et utiliser this avant provoque TS17009 ('super' must be called before accessing 'this' in the constructor of a derived class). Les deux reflètent des règles d'exécution de JavaScript.
class Animal {
constructor(public name: string) {}
}
class Dog extends Animal {
tricks: string[];
constructor(name: string, ...tricks: string[]) {
super(name); // must come first
this.tricks = tricks;
}
}
const rex = new Dog("Rex", "sit", "roll");
console.log(rex); // Dog { name: 'Rex', tricks: [ 'sit', 'roll' ] }
Une sous-classe qui n'ajoute pas de constructeur hérite de celui du parent, avec les mêmes types de paramètres. Plus de détails sur les sous-classes dans héritage.
Constructeurs privés et initialisation asynchrone
Un constructeur private ne peut être appelé que depuis l'intérieur de la classe. À l'extérieur, new provoque l'erreur TS2673. C'est ainsi qu'on oblige les appelants à passer par une fabrique, pour un singleton ou pour une initialisation qui doit être asynchrone (les constructeurs ne peuvent pas être async).
Ici, private n'est qu'une règle de compilation. Le JavaScript émis a un constructeur ordinaire, donc du code JavaScript pur pourrait toujours appeler new Connection(...).
Types de constructeurs
Pour accepter une classe en tant que valeur, typez le paramètre avec une signature de construction : new (...args) => Instance. typeof MyClass fonctionne aussi, mais il lie le paramètre à la signature du constructeur et aux membres statiques de cette seule classe.
ConstructorParameters et InstanceType extraient le tuple des paramètres et le type d'instance d'un type de constructeur ; ils sont présentés avec les autres helpers de fonctions dans ReturnType et Parameters.
Questions fréquentes
Que sont les propriétés de paramètres en TypeScript ?
Un paramètre de constructeur doté d'un modificateur (public, private, protected ou readonly) déclare un champ et l'assigne en une seule étape. constructor(private name: string) {} est un raccourci pour déclarer private name: string et écrire this.name = name. Le compilateur génère cette assignation dans la sortie.
Une classe TypeScript peut-elle avoir plusieurs constructeurs ?
Pas plusieurs implémentations. Une classe a un seul constructeur, mais vous pouvez écrire au-dessus plusieurs signatures de surcharge pour que les appelants voient des listes de paramètres distinctes. Des méthodes de fabrique statiques comme Color.fromHex() et Color.fromRgb() sont souvent plus claires que des surcharges.
Un constructeur peut-il être async en TypeScript ?
Non. Un constructeur renvoie toujours la nouvelle instance, jamais une promesse, et async constructor() est refusé avec l'erreur TS1089 ('async' modifier cannot appear on a constructor declaration). Utilisez un constructeur privé plus une méthode statique async create() qui fait le travail asynchrone puis appelle new.
Comment typer un constructeur de classe passé en paramètre ?
Utilisez une signature de construction : new (name: string) => User, ou typeof User pour cette classe précise. Une fabrique générique ressemble à function make<T>(ctor: new () => T): T { return new ctor(); }. ConstructorParameters<typeof User> donne la liste des paramètres sous forme de tuple.
Pourquoi obtient-on « 'super' must be called before accessing 'this' » ?
C'est l'erreur TS17009. Dans une classe qui étend (extends) une autre classe, c'est le constructeur parent qui crée l'objet : this n'existe donc pas tant que super(...) ne s'est pas exécuté. Placez l'appel à super au-dessus de toute ligne qui utilise this.