#javascript #typescript
#javascript #typescript
Вопрос:
Вот простой пример того, чего я пытаюсь достичь. В этом примере у меня есть несколько классов animal и класс Farm, который служит фабрикой для данного типа animal:
class Farm<T> {
farmAnimal: any;
animals: Array<T> = [];
constructor(farmAnimal: new() => T, farmSize: number) {
this.farmAnimal = farmAnimal;
for(let i =0; i<farmSize; i ) {
this.animals.push(new this.farmAnimal());
}
}
}
class Pig {
doThing(){}
}
class Sheep {
doThing(){}
}
Это работает, но моя проблема в том, что я могу сделать что-то подобное:
let farm = new Farm<Pig>(Sheep, 10);
Проблема, похоже, в том, что new() => T
тип в конструкторе фермы не обеспечивает принудительное применение переданного типа конструктора.
Есть ли лучший способ сделать это, чтобы TypeScript не воспринимал new Farm<Pig>(Sheep, 10)
как допустимый?
Комментарии:
1. Исправление синтаксических ошибок, нет, вы не можете сделать,
new Farm<Pig>(Sheep, 10);
Может быть, опубликовать более полный пример typescriptlang.org/play ? #code/…2. Я думаю, это потому, что мои классы имеют одинаковую подпись. Смотрите: typescriptlang.org/play ? #code/…
3. Это в любом случае, чтобы избежать этого?
Ответ №1:
Проблема в том, что два класса структурно одинаковы. Typescript использует структурную типизацию, поэтому, если два типа структурно одинаковы, они эквивалентны, это относится даже к классам.
Самый простой способ убедиться, что классы не могут быть псевдонимами, — это добавить личное поле в . Даже если имя такое же, поскольку оно частное, оно не будет структурно эквивалентным.
class Factory<T> {
private objs: Array<T> = [];
private objClass: any;
constructor(objClass: new () => T) {
this.objClass = objClass;
this.objs.push(new this.objClass());
}
}
class Test{
private _notAliased: undefined;
test() {
}
}
class Test2{
private _notAliased: undefined;
test() {
}
}
let p1 = new Factory<Test>(Test2); // error now
Ответ №2:
Как вы можете видеть из этой ссылки на typescript playground, то, что вы говорите, неверно. Вы не можете этого сделать new Farm<Pig>(Sheep, 10);
.
Вот код, определяющий, когда typescript playground когда-либо отключается:
class Farm<T> {
farmAnimal: any;
animals: Array<T> = [];
constructor(farmAnimal: new() => T, farmSize: number) {
this.farmAnimal = farmAnimal;
for(let i=0; i < farmSize; i ) {
this.animals.push(new this.farmAnimal());
}
}
}
class Pig {
doPigThing(): void {
}
}
class Sheep {
doSheepThing(): void {
}
}
const animal = new Farm<Sheep>(Pig, 3); // Compiler error:
Ошибка компилятора:
Argument of type 'typeof Pig' is not assignable to parameter of type 'new () => Sheep'. Property 'doSheepThing' is missing in type 'Pig' but required in type 'Sheep'.
Комментарии:
1. Привет, да, ты прав. Мне следовало проверить свой код, когда я его писал. Похоже, в моем реальном коде проблема в том, что мои классы имеют одинаковую подпись. Это компилируется, несмотря на то, что это разные классы: typescriptlang.org/play ? #code/…
2. Это потому, что ваши классы представляют один и тот же структурный тип.
{ test: () => void }