Why doesn't the type parameter of this generic function accept the given type?

半世苍凉 提交于 2020-12-15 06:52:28

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!