I want to specify the shape of some data on a subclass and a generator which creates classes with some generic T
. My initial thought is to use generics as below (simplified example), but when I call makeMyClass
and when I return new classRef
, it gives me the following error:
Type 'T' is not assignable to type 'DataInterface'
Why isn't T
of type DataInterface
?
class MySuperClass<T> {
constructor(public data: T) {}
}
interface DataInterface {
name: string;
}
let initData: DataInterface = {
name: "Alice"
};
class MyClass extends MySuperClass<DataInterface>{
constructor(public data: DataInterface) {
super(data)
}
}
function makeMyClass<T>(classRef: typeof MySuperClass): MySuperClass<T> {
return new classRef(initData);
}
let a = makeMyClass<DataInterface>(MyClass);
let b = a.data
Well, you have two problems in your code. The first is that you are defining makeMyClass
as generic, but then you invoke new classRef
with a concrete variable. This means that T
can't really be anything, it must be of type type initData
.
Apart from that, you are declaring classRef
as the type of a class. It should better be defined as a constructor signature, or you'll have problems with let a = makeMyClass<>(MyClass)
Your code will work with these changes:
function makeMyClass<T>(classRef: new(initData: T) => MySuperClass<T>, initData: T): MySuperClass<T> {
return new classRef(initData);
}
let a = makeMyClass(MyClass, initData);
let b = a.data
the signature new(initData: T) => MySuperClass<T>
means, *a constructor that accepts a parameter of type T, and creates an object of type MySuperClass<T>
. Both MySuperClass<DataInterface>
and MyClass
comply with this requirement. However, you'll find that MyClass
is not assignable to a parameter of type typeof MySuperClass
. Besides, the use of a constructor type will restrict the kind of constructors you can pass to those which have that exact signature. If you create a new derived class from MySuperClass
but it has a constructor with two arguments, it won't be possible to use it with this function, as it expects a constructor that needs just one argument of type T
. This prevents runtime errors, so you can't invoke a constructor with less parameters than it expects.
And, of course, if you want the function to be generic, you need to pass the second parameter, of type T
, to pass to the constructor of the class. Otherwise, as I explained, the function can't really be generic, as it is restricted to the type of initData
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.