jas7457
jas7457

Reputation: 1782

TypeScript array of generic classes

I'm having trouble getting the TypeScript compiler to not give me grief. I have a controller which has an array of classes, NOT the instance of the class, but the class itself. All of these will extend off of the same base, UnitView. For some reason I get an error if my TitleView does not also accept generics, but I get no errors if it does.

I'm not understanding why TitleView would need to accept generics because it passes the Model type explicitly to the UnitView. Can anyone explain or see anything that I'm doing wrong?

Code:

class Model { }
class View<TModel extends Model> {
    private model: TModel;
}

class UnitView<TModel extends Model> extends View<TModel> { }

class TitleView extends UnitView<Model> { }


class Controller {
    private ViewClass: typeof UnitView;

    private ViewClasses: typeof UnitView[] = [
        TitleView
    ]
}

And here is a direct link to TypeScript playground if you want to test it there

Upvotes: 0

Views: 2845

Answers (2)

basarat
basarat

Reputation: 276199

The error has nothing to do with arrays. Here is a minimal reproduction of your bug:

class View<TModel> {
    model: TModel;
}

class UnitView<TModel> extends View<TModel> { }
class TitleView extends UnitView<{}> { }

const example1: typeof UnitView = TitleView; // ERROR 

TileView is not assignable to typeof UnitView. The key reason being that the type of T (a generic) are not compatible with {}.

This is similar to the further simplified example shown below:

class Foo<T> { 
    model: T
}
class Bar{
    model: {}
}

const example2: typeof Foo = Bar; // ERROR 

TLDR

Generics T and instances (even {}) are not compatible for assignment. This is by design.

More

The only way to stay compatible is the preserve the generic as well e.g.

class Foo<T> { 
    model: T
}
class Bar<T>{
    model: T
}

const example3: typeof Foo = Bar; // Okay 

Upvotes: 2

Ryan Cavanaugh
Ryan Cavanaugh

Reputation: 220904

To complement basarat's answer, here's a working declaration:

private ViewClasses: (new (...args: any[]) => UnitView<{}>)[] = [
    TitleView
]

Upvotes: 0

Related Questions