I have this function
public getCollection<T>(collectionType: T): Collection<T> {
return new Collection<T>("some-arg1", "some-arg2")
}
and in Collection
class I have this
export class Collection<T> {
public add (T item) {
// .. logic
}
}
I have a user class defined like this
export class Student {
}
and when I attempt to do
getCollection(Student).add(new Student());
There is an error
TS2345: Argument of type 'Student' is not assignable to parameter of type 'typeof Student'. Property 'prototype' is missing in type 'Student' but required in type 'typeof Student'.
Following works fine.
new Collection<Student>().add( new Student());
So what is wrong when the function returns generic collection?
CodePudding user response:
T
is actually of type typeof Student
. Student
is an instance of the class, while typeof Student
is the constructor. To get the instance type of a constructor, use the intuitively named InstanceType
built-in:
public getCollection<T>(collectionType: T): Collection<InstanceType<T>> {
return new Collection<InstanceType<T>>("some-arg1", "some-arg2")
}
But now you have to add a constraint which shouldn't be too much of a problem:
public getCollection<T extends new (...args: any[]) => any>(...
This should result in:
public getCollection<T extends new (...args: any[]) => any>(collectionType: T): Collection<InstanceType<T>> {
return new Collection<InstanceType<T>>("some-arg1", "some-arg2")
}
CodePudding user response:
This error is caused due to the fact that the generic type is inferred from the parameter; meaning that T
is not Student
but it is actually typeof Student
. Hence return new Collection<T>
does not behave like return new Collection<Student>
but is instead return new Collection<typeof Student>
.
This can be fixed by actually assigning a type to the generic parameter:
getCollection<Student>(Student)
The above makes the use of the parameter redundant, hence getCollection
can be refactored to the following:
getCollection<T>(): Collection<T> {
return new Collection<T>("some-arg1", "some-arg2");
}
and be called as:
getCollection<Student>()
Link to the playground.