web-dev-qa-db-fra.com

Type de constructeur de classe en dactylographié?

Comment déclarer un type class afin de m'assurer que l'objet est un constructeur d'une classe générale?

Dans l'exemple suivant, je veux savoir quel type dois-je donner à AnimalClass pour qu'il soit soit Penguin ou Lion:

class Animal {
    constructor() {
        console.log("Animal");
    }
}

class Penguin extends Animal {
    constructor() {
        super();
        console.log("Penguin");
    }
}

class Lion extends Animal {
    constructor() {
        super();
        console.log("Lion");
    }
}

class Zoo {
    AnimalClass: class // AnimalClass could be 'Lion' or 'Penguin'

    constructor(AnimalClass: class) {
        this.AnimalClass = AnimalClass
        let Hector = new AnimalClass();
    }
}

Bien sûr, le type class ne fonctionne pas et serait de toute façon trop général.

49
arthur.sw

Je ne sais pas si cela était possible dans TypeScript lorsque la question a été posée à l'origine, mais ma solution préférée est d'utiliser génériques:

class Zoo<T extends Animal> {
    constructor(public readonly AnimalClass: new () => T) {
    }
}

De cette manière, les variables penguin et lion déduisent le type concret Penguin ou Lion même dans le typeScript intellisense.

const penguinZoo = new Zoo(Penguin);
const penguin = new penguinZoo.AnimalClass(); // `penguin` is of `Penguin` type.

const lionZoo = new Zoo(Lion);
const lion = new lionZoo.AnimalClass(); // `lion` is `Lion` type.
1
Nenad

Solution de référence des interfaces TypeScript :

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}
class AnalogClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("tick tock");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

Ainsi, l'exemple précédent devient:

interface AnimalConstructor {
    new (): Animal;
}

class Animal {
    constructor() {
        console.log("Animal");
    }
}

class Penguin extends Animal {
    constructor() {
        super();
        console.log("Penguin");
    }
}

class Lion extends Animal {
    constructor() {
        super();
        console.log("Lion");
    }
}

class Zoo {
    AnimalClass: AnimalConstructor // AnimalClass can be 'Lion' or 'Penguin'

    constructor(AnimalClass: AnimalConstructor) {
        this.AnimalClass = AnimalClass
        let Hector = new AnimalClass();
    }
}
50
arthur.sw

Comme ça:

class Zoo {
    AnimalClass: typeof Animal;

    constructor(AnimalClass: typeof Animal ) {
        this.AnimalClass = AnimalClass
        let Hector = new AnimalClass();
    }
}

Ou juste:

class Zoo {
    constructor(public AnimalClass: typeof Animal ) {
        let Hector = new AnimalClass();
    }
}

typeof Class est le type du constructeur de la classe. Il est préférable à la déclaration de type de constructeur personnalisé, car elle traite correctement les membres de la classe statique.

Voici la partie pertinente de Docs TypeScript . Rechercher le typeof. Dans le cadre d'une annotation de type TypeScript, cela signifie "donnez-moi le type du symbole appelé Animal", qui est le type de la fonction constructeur de la classe dans notre cas.

12
gaperton

Comment déclarer un type de classe afin de m'assurer que l'objet est un constructeur d'une classe générale?

Un type de constructeur peut être défini comme:

 type AConstructorTypeOf<T> = new (...args:any[]) => T;

 class A { ... }

 function factory(Ctor: AConstructorTypeOf<A>){
   return new Ctor();
 }

const aInstance = factory(A);
1
AleC