问题
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
回答1:
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.
来源:https://stackoverflow.com/questions/50183476/why-doesnt-the-type-parameter-of-this-generic-function-accept-the-given-type