J'ai créé une usine qui créera des instances de certaines classes. Je veux utiliser des génériques pour m'assurer que tous les objets retournés proviennent de sous-classes qui étendent des classes abstraites.
Je pensais que la logique de la méthode createInstance
montrée ci-dessous pourrait être décrite comme 'createInstance () retournera un type T
qui est contraint à être une classe qui étend Animal.
Comme vous pouvez le voir, Lion étend Animal, mais je reçois toujours l'avertissement du compilateur type Lion is not assignable to type T
.
abstract class Animal {
abstract makeSound(): void;
}
class Bear extends Animal {
public makeSound() {
console.log('growl');
}
}
class Lion extends Animal {
public makeSound() {
console.log('roar');
}
}
function createInstance<T extends Animal>(type: string): T {
switch(type) {
case 'bear':
return new Bear(); // 'type Bear is not assignable to type T'
case 'lion':
return new Lion(); // 'type Lion is not assignable to type T'
}
}
createInstance().makeSound();
J'ai lu à la fin des documents TypeScript Generics que:
Lors de la création d'usines en TypeScript à l'aide de génériques, il est nécessaire de faire référence aux types de classe par leurs fonctions constructeurs. Par exemple,
function create<T>(c: {new(): T; }): T { return new c(); }
mais je ne veux pas vraiment avoir à passer le constructeur de classe dans la fonction si possible et je voudrais comprendre pourquoi je reçois le not assignable to type T
message en premier lieu.
Merci
Si votre fonction retourne toujours un Lion
son type de résultat n'est pas vraiment générique. Vous pouvez par exemple écrire create<Tiger>()
et votre fonction retournera toujours un Lion
. Une véritable fonction générique retournerait une valeur qui respecte le paramètre générique.
Vous pouvez passer le constructeur en argument, comme vous l'avez découvert:
function create<T>(c: {new(): T; }): T {
return new c();
}
Ou vous pouvez rendre votre fonction non générique et lui faire retourner un Animal
ou un Lion
. Vous pourriez avoir plus de surcharges, si vous avez une logique basée sur des valeurs d'argument qui déterminent le type de retour:
// Public signatures, we tie function parameter values to return value for specific types
function createInstance(type: "Lion"): Lion
function createInstance(type: "Tiger"): Tiger
// Private signature, not visible from outside
function createInstance(type: "Lion" | "Tiger"): Animal {
if(type === "Lion") {
return new Lion();
}
else if(type === "Tiger") {
return new Tiger();
}
}
let tiger = createInstance("Tiger"); // will be typed as Tiger
let lion = createInstance("Lion");// will be typed as Lion
let err = createInstance("Lama");// will be an error since the function does not know how to create a Lama