web-dev-qa-db-fra.com

Surcharge du constructeur TypeScript avec le constructeur vide

Pourquoi n’est-il pas permis d’avoir des séparations distinctes deconstructordans TypeScript ?
Avoir par exemple deuxconstructors, je dois écrire mon code comme ceci. 

constructor(id: number)
constructor(id: number, name?: string, surname?: string, email?: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

Ainsi, je dois mettre ? après les choses que je veux ne pas être nécessaires. 

Pourquoi ne puis-je pas l'écrire comme ça?

constructor(id: number) {
    this.id = id;
}

constructor(id: number, name: string, surname: string, email: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

Ainsi, pour chaque constructeur, tous les paramètres sont obligatoires.

De plus, j'ai besoin d'un constructeur vide. Cela devient encore plus étrange, car je dois marquer chaque paramètre avec un ?.

constructor()
constructor(id?: number, name?: string, surname?: string, email?: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

Pourquoi TypeScript diffère-t-il des langages courants tels que C# ou Python ici?

Je m'attendrais à ce que cela fonctionne comme ça.

constructor() {

}
constructor(id: number, name: string, surname: string, email: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

Ainsi, vous pouvez passer aucun paramètre ou devez passer des paramètres.

24
Daniel Hitzel

Parce que votre implémentation de constructeur est appelée par tous vos constructeurs de surcharge. (Techniquement, au moment de l'exécution, une seule fonction constructeur est appelée avec les différentes signatures d'argument de surcharge.) 

Imaginez ça comme ça:

overload_constructor(id:string) {
    implementation_constructor(id);
}

implementation_constructor(id:string, name?:string, age?:number) {
    // ...
}

En pensant de cette façon, overload_constructor ne pourrait pas appeler implementation_constructor à moins que name et age soient facultatifs.

Voir également la réponse de Basarat, l'implémentation n'est pas exposée à une utilisation publique par le vérificateur de types (bien qu'au moment de l'exécution, ce soit le "vrai" constructeur utilisé dans JS). Si vous voulez n'autoriser que (), (id) ou (id, name, surname, email) comme seules signatures d'appel valides, procédez comme suit:

constructor()
constructor(id: number)
constructor(id: number, name: string, surname: string, email: string)
constructor(id?: number, name?: string, surname?: string, email?: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

Notez que dans l'implémentation, tous les paramètres sont facultatifs, mais cette signature n'est pas exposée lors de la compilation et vous ne pouvez utiliser que ces appels:

new Foo()
new Foo(1)
new Foo(1, "a", "b", "c")

Non, par exemple:

new Foo(1, "a")
17
Aaron

La dernière surcharge de fonction est uniquement utilisée dans l'implémentation et n'est pas disponible publiquement. Ceci est montré ci-dessous: 

class Foo{
    constructor()
    constructor(id?: number) {
    }
}

const foo1 = new Foo();
const foo2 = new Foo(123); // Error! : not public

Si vous souhaitez que id:number soit disponible publiquement, vous pouvez ajouter une autre surcharge: 

class Foo{
    constructor()
    constructor(id: number)
    constructor(id?: number) {
    }
}

const foo1 = new Foo();
const foo2 = new Foo(123); // Okay
const foo3 = new Foo('hello'); // Error: Does not match any public overload

La raison en est que TypeScript essaie de ne pas générer de code sophistiqué pour la surcharge de fonctions (les langages traditionnels le font en utilisant des noms tels que C++).

Ainsi, vous pouvez passer aucun paramètre ou devez passer des paramètres.

En réalité, vous pouvez rendre la surcharge finale facultative, mais aucune des surcharges publiques n'est facultative. Prenons l'exemple suivant: 

class Foo{  
    constructor(id: number, name:string)
    constructor(name:string)
    constructor(idOrName?: number|string, name?:string) {
    }
}

const foo1 = new Foo('name'); // Okay
const foo2 = new Foo(123); // Error: you must provide a name if you use the id overload
const foo3 = new Foo(123,'name'); // Okay
22
basarat

Vous pouvez utiliser le modèle Builder pour résoudre ce problème. Même en C # ou en Python, cela devient rapidement une meilleure approche à mesure que le nombre d'arguments de constructeur augmente.

class Foo {
  constructor(public id: number, public name: string, public surname: string, public email: string) {
  }
  static Builder = class {
    id: number = NaN;
    name: string = null;
    surname: string = null;
    email: string = null;
    Builder() {
    }
    build(): Foo {
      return new Foo(this.id, this.name, this.surname, this.email);
    }
  }
}
0
PeeWee2201