Тип конструктора классов в typescript?

Как я могу объявить тип class, чтобы гарантировать, что объект является конструктором общего класса?

В следующем примере я хочу знать, какой тип я должен указывать на AnimalClass, чтобы он мог быть Penguin или 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();
    }
}

Конечно, тип class не работает, и в любом случае он будет слишком общим.

Ответы

Ответ 1

Я не уверен, было ли это возможно в TypeScript, когда вопрос был задан изначально, но я предпочел решение с использованием обобщений:

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

Таким образом, переменные penguin и lion выводят конкретный тип Penguin или Lion даже в IntelliSense TypeScript.

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.

Ответ 2

Решение 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);

Итак, предыдущий пример:

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();
    }
}

Ответ 3

Вот так:

class Zoo {
    AnimalClass: typeof Animal;

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

Или просто:

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

typeof Class - это тип конструктора класса. Это предпочтительнее объявления типа пользовательского конструктора, потому что оно обрабатывает статические члены класса должным образом.

Здесь соответствующая часть документов TypeScript. Найдите typeof. Как часть аннотации типа TypeScript, это означает "дайте мне тип символа с именем Animal", который является типом функции конструктора класса в нашем случае.

Ответ 4

Как я могу объявить тип класса, чтобы убедиться, что объект является конструктором общего класса?

Тип конструктора может быть определен как:

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

 class A { ... }

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

const aInstance = factory(A);