简体   繁体   中英

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

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM