I need to create an array that can hold any number of items, all of which are subclasses of the same base class. The issue I'm facing is with type checking in TypeScript - when I declare the array as Array<BaseClass>
, I have to cast each item to its specific subclass for accurate type checking. This defeats the purpose of class polymorphism.
To illustrate:
class Base {
name: string
}
class Sub1 extends Base {
prop1: number
}
class Sub2 extends Base {
prop2:string
}
// there will be other Base subclasses - unknown quantity, possibly from third party plugins
// public function called by end users - I want precise type checking on object literals without manual casting:
function f(arr: Base[]){
}
// TypeScript incorrectly assumes every item is Sub1, even if explicitly defining one as Sub2:
f([
{name: '1', prop1: 1} as Sub1,
{name: '1', prop2: '2'} as Sub2,
])
// Requires casting but performs proper typechecking:
f([
{name: '1', prop1: 1},
{name: '1', prop2: '2'},
] as [Sub1, Sub2])
When calling overloaded methods or functions in similar situations, TypeScript matches signatures without needing casts. Is this avoidance intentional due to potential performance issues with large arrays?
For users to call f()
elegantly without forced casting, I am seeking a way to achieve exact type checking without manual casting. In an object-oriented language, such as Java, instances of subclasses should not require casting since they are still instances of the base class.
Note: Unable to use a type union (arr: Array<Sub1|Sub2>
) as I do not know all possible subclasses provided by third parties.
In languages like Java, you would declare the array as Array<? extends Base>
. Perhaps TypeScript has a similar feature that I am unaware of.
Thank you!