0

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

2 Answers 2

2

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 
Sign up to request clarification or add additional context in comments.

3 Comments

So what would be the correct way to write this if I want to express the array will be an array of classes that extend off of UnitView?
You will have to preserve the generic. Added to answer as more 🌹
I was hoping there'd be another way, as the TitleView really shouldn't be accepting generics, as that is the end of the line and the Model is well-defined at that point. I may just change the typings to an array of any instead. This design seems flawed to me, or maybe I just don't fully understand it. Thanks for the help.
0

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.