Reputation: 332
I am trying to extend a class with two levels of inheritance with generics, like the following diagram:
First attempt, I declared BaseResourceTableComponent
as extending BaseResourceListComponent<T extends BaseResourceModel>
:
export abstract class BaseResourceModel {
public id?: number;
}
export abstract class BaseResourceListComponent<T extends BaseResourceModel> {
public resources: T[] = [];
...
}
export abstract class BaseResourceTableComponent extends BaseResourceListComponent<T extends BaseResourceModel> { // <--- ERROR!
dataSource: MatTableDataSource<T>;
...
}
// now, the non abstract classes
export class User extends BaseResourceModel {
constructor(
public name?: string,
) {
super();
}
export class UserTableComponent extends BaseResourceTableComponent<User> {
...
}
I get the following error:
error TS2304: Cannot find name 'T'.
Second attempt, I declared BaseResourceTableComponent
as extending BaseResourceListComponent<BaseResourceModel>
(without the T extents
):
export abstract class BaseResourceModel {
public id?: number;
}
export abstract class BaseResourceListComponent<T extends BaseResourceModel> {
public resources: T[] = [];
...
}
export abstract class BaseResourceTableComponent extends BaseResourceListComponent<BaseResourceModel> {
dataSource: MatTableDataSource<BaseResourceModel>;
...
}
// now, the non abstract classes
export class User extends BaseResourceModel {
constructor(
public name?: string,
) {
super();
}
export class UserTableComponent extends BaseResourceTableComponent<User> { // <--- ERROR!
...
}
It passes, no error in the BaseResourceTableComponent
declaration but I get the following error further on UserTableComponent
declaration:
error TS2315: Type 'BaseResourceTableComponent' is not generic.
I am really confused here!
Am I missing something? Workarounds?
Upvotes: 0
Views: 1676
Reputation: 11934
export abstract class BaseResourceListComponent<T extends BaseResourceModel> {
public resources: T[] = [];
...
}
Here you define the BaseResourceListComponent
class with a generic type T extends BaseResourceModel
. The extends BaseResourceModel
part is a type constraint which imposes restrictions on the types T
can have. What this means is that T
must either be BaseResourceModel
or one of its subtypes.
A type B
is a subtype of A
if B
is of type A
and has additional information(i.e: properties, methods).
export abstract class BaseResourceTableComponent extends BaseResourceListComponent<T extends BaseResourceModel> { // <--- ERROR!
dataSource: MatTableDataSource<T>;
...
}
Here you get an error because BaseResourceListComponent
expects a type, and here you provide T extends BaseResourceModel
, but you haven't defined T
at all.
You could solve it with
export abstract class BaseResourceTableComponent<T extends BaseResourceModel> extends BaseResourceListComponent<T> { }
Now, T
is a type, no matter if it's concrete or generic, as long as T
fulfills the constraint: extends BaseResourceModel
.
Upvotes: 1
Reputation: 2443
Both of your problems are caused by BaseResourceTableComponent not being declared generic.
export abstract class BaseResourceTableComponent extends BaseResourceListComponent<T extends BaseResourceModel>
says that the generic parameter for BaseResourceListComponent
is T
, but doesn't give anyway to determine what T
is because BaseResourceTableComponent
neither specifies a concrete parameter nor gives a way to declare a generic parameter that can be essentially passed down to the parent class.
Extending a generic class does not make the class doing the extending generic; In fact, you're trying to rely on exactly that with export class UserTableComponent extends BaseResourceTableComponent<User>
.
Upvotes: 0