I've encountered a typings issue while working on a new feature for my TypeScript
library. Let's dive into the problem with the following example:
class Base { ... }
class User extends Base { ... }
class Product extends Base { ... }
class CompletelyUnrelated { ... }
function someFunction<TModel>(source: TModel, base: {what_to_type_here}) { ... };
// Desired outcome
someFunction(User, Base); // works
someFunction(Product, Base); // works
someFunction(CompletelyUnrelated, Base); // error
someFunction(User, Product); // error
someFunction(Product, User); // error
someFunction(User, CompletelyUnrelated); // error
My goal is for someFunction()
to only accept User
and Base
as its arguments due to the inheritance relationship between them. The same applies for Product
and Base
. Is there a feasible solution for this requirement? Is there any approach that aligns with my objective?
I've attempted:
interface Constructible<TModel> { // an interface to denote a new-able type (included here for context)
new(...args: any[]): TModel;
}
type BaseConstructible<TModel> = TModel extends infer TBase ? Constructible<TBase> : any;
However, the outcome always yields Constructible<TModel>
:
type Test = BaseConstructible<User>; // returns Constructible<User>
Any assistance or direction on this matter would be greatly appreciated. Thank you
UPDATE: Acknowledging @jcalz's point about TypeScript
having a structural type system, I am well aware of this fact. While @jcalz's response is accurate, it doesn't completely address my specific requirement. Consider this scenario:
function anotherFunction<TBase , TModel extends TBase>(source: Constructible<TModel>) {
return (base: Constructible<TBase>) => {
// function body
}
}
anotherFunction(User)(Product); // no error
TypeScript
struggles to infer TBase
from TModel extends TBase
. Is there a way to make TypeScript
infer TBase
in this context?