I have a bunch of model classes that each have a model type. I also have a "TypeToModel" helper to get the model class given a model type. I.e.:
type BaseModel = { id: number };
type Models = {
user: BaseModel & { name: string },
post: BaseModel & { title: string },
};
type ModelType = 'user' | 'post';
type TypeToModel<T extends keyof Models> = ModelType extends T
? BaseModel
: Models[T];
function getModel<T extends ModelType>(
modelType: T,
): TypeToModel<T> {
return {} as unknown as TypeToModel<T>;
}
If a single model type is passed to getModel
, I want the return type to be the model's type. If the entire ModelType union gets passed to getModel
, I want it to return BaseModel
. This works most of the time:
const userA = getModel('user'); // userA = BaseModel & { name: string }
const userB = getModel('user' as ModelType); // userB = BaseModel
However, if a variable with a generic type gets passed to getModel
, it returns a union of all the models. E.g.:
function foo<T extends ModelType>(modelType: T) {
const userC = getModel(modelType);
userC.id;
/*
userC = BaseModel
| (BaseModel & { name: string })
| (BaseModel & { title: string })
*/
}
I expected userC
to be BaseModel
, but it's a union of all the models. I want to detect if it would return a union of all the models and make it return BaseModel
instead. I tried using IsUnion<>, but it was false
for both T
and userC
.
How can I check if getModel
's argument has a generic type? In other words, is it possible to write an IsGeneric<>
utility type?