Problem
You might be familiar of the fact that a subtype can be assigned to a supertype but vice-versa is not true. So, in the following code and the inline explanation-
class A extends Array<string> {
public myProp!: string
}
// it is ok to assign a subtype to its supertype
// because subtype has atleast all those props/methods
// that a supertype has
declare const a1: A
const array1: Array<string> = a1
// it is an error to assign supertype to one of its subtype
// (until they are structurally same)
// because the supertype (array2) may have some missing props/methods
// (myProp in this case) that its subtype has.
declare const array2: Array<string>
const a2: A = array2
Playground
In your code, TItems
is a subtype of Array<string>
, and type of []
is never[]
.
If you had typecast-ed it with [] as Array<string>
, the supertype (Array<string>
) could not be assigned to subtype TItems
. Playground
If you had typecast-ed it with [] as TItems
, the typecasting is itself erroneous for the very same reason. Playground
Solution
The error could be get ridden of the error with typecasting as-
class MyClass<TItems extends Array<string>> {
public items: TItems;
constructor() {
this.items = [] as unknown as TItems;
}
}
Playground
But this may result in runtime errors because it's not a "safe" typecasting.
To avoid runtime errors, the correct way is to initialise the prop items
with the constructor of the class TItems
or function that returns TItems
instead of = []
. This will eliminate the type errors and also will ensure that there will be no runtime errors. Both ways are demonstrated-
// if a passed TItems is supposed to class
// we pass that constructor of the class
// constructor of `MyClass`
class MyClass<TItems extends Array<string>> {
public items: TItems;
constructor(ctor: new () => TItems) {
this.items = new ctor();
}
}
class MyArray extends Array<string> {
private myProp!: string
}
const myClassVar = new MyClass(MyArray)
Playground
// if a passed TItems is supposed to be just a type
// we pass a function that will create that object of `TItems`
class MyClass<TItems extends Array<string>> {
public items: TItems;
constructor(fn: () => TItems) {
this.items = fn();
}
}
declare function createObject(): Array<string> & { myProp: string }
const myClassVar = new MyClass(createObject)
Playground