Reputation: 1258
Here is a simple example of what I'm trying to achieve. In this example I have some animal classes and a Farm class which serves as a factory for a given animal type:
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(){}
}
This works, but my problem is I can do thing like this:
let farm = new Farm<Pig>(Sheep, 10);
The issue seems to be with the new() => T
type in the Farm constructor not enforcing the type of constructor passed in.
Is there a better way to do this so TypeScript doesn't see new Farm<Pig>(Sheep, 10)
as valid?
Upvotes: 1
Views: 41
Reputation: 249536
The problem is that the two classes are structurally the same. Typescript uses structural typing, so if two types are structurally the same they are equivalent, this applies even to classes.
The simplest way to ensure that the classes are not aliasable is to add a private field to the. Even if the name is same, since it is private it will not be structurally equivalent.
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
Upvotes: 2
Reputation: 11456
As you can see from this typescript playground link, what you are saying is incorrect. You can not do new Farm<Pig>(Sheep, 10);
.
Here is the code for when the typescript playground ever goes offline:
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:
The compiler error is:
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'.
Upvotes: 2