First of all we need to know that typeof UserType and UserType are two different types.
First type typeof UserType is a type of class constructor.
Second type UserType is a type of UserType class instance.
In this case, I think it is better to use HashMap data structure instead of switch.
Consider this:
abstract class UserType { }
abstract class EmpRoleType extends UserType { }
abstract class ClientRoleType extends UserType { }
class EmpSupport extends EmpRoleType { }
class ClientSupport extends ClientRoleType { }
const ClassMap = {
'EmpSupport': class EmpSupport extends EmpRoleType { },
'ClientSupport': class ClientSupport extends ClientRoleType { }
} as const;
In this case we don't need switch anymore.
Now we can define getUserType function:
type Values<T> = T[keyof T];
function hasProperty<Obj>(obj: Obj, prop: any): prop is keyof Obj {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
const withMap = <
Key extends PropertyKey,
Klass extends new () => any,
ClassMap extends Record<Key, Klass>
>(
classMap: ClassMap
) => {
return function GetValue<Role extends PropertyKey>(
role: Role
): Values<ClassMap> | null {
if (hasProperty(classMap, role)) {
return classMap[role];
}
return null;
};
};
Now we define variable to access that function with the correct map
const GetUserType = withMap(ClassMap);
Now we can get the class type by passing a string to the function.
const userType = GetUserType('EmpSupport'); // typeof EmpSupport
Note: if a key is passed to the function it will return null
Eg. GetUserType('bad entry');
If you want to create instance of GetUserType retuen value you need to use extra parentheses
const userType = new (GetUserType('EmpSupport'))(); // EmpSupport
allowPermission should be a typeguard written as follow:
function allowParentPermission<Allowed extends typeof UserType>(
AllowParentRole: Allowed,
userRole: unknown
): userRole is InstanceType<Allowed> {
return userRole instanceof AllowParentRole;
}
By convention, all classes should be capitalized, that's why I have written AllowParentRole instead of allowParentRole
Whole code:
abstract class UserType { }
abstract class EmpRoleType extends UserType { }
abstract class ClientRoleType extends UserType { }
class EmpSupport extends EmpRoleType { }
class ClientSupport extends ClientRoleType { }
const ClassMap = {
'EmpSupport': class EmpSupport extends EmpRoleType { },
'ClientSupport': class ClientSupport extends ClientRoleType { }
} as const;
type Values<T> = T[keyof T];
function hasProperty<Obj>(obj: Obj, prop: any): prop is keyof Obj {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
const withMap = <
Key extends PropertyKey,
Klass extends new () => any,
ClassMap extends Record<Key, Klass>
>(
classMap: ClassMap
) => {
return function GetValue<Role extends PropertyKey>(
role: Role
): Values<ClassMap> | null {
if (hasProperty(classMap, role)) {
return classMap[role];
}
return null;
};
};
function allowParentPermission<Allowed extends typeof UserType>(
AllowParentRole: Allowed,
userRole: unknown
): userRole is InstanceType<Allowed> {
return userRole instanceof AllowParentRole;
}
Playground
UPDATE
userRole is - is a special syntax for type guards
UPDATE 2
abstract class UserType { }
abstract class EmpRoleType extends UserType { }
abstract class ClientRoleType extends UserType { }
class EmpSupport extends EmpRoleType { }
class ClientSupport extends ClientRoleType { }
const ClassMap = {
'EmpSupport': class EmpSupport extends EmpRoleType { },
'ClientSupport': class ClientSupport extends ClientRoleType { }
} as const;
const hasProperty = <Obj,>(obj: Obj, prop: any)
: prop is keyof Obj =>
Object.prototype.hasOwnProperty.call(obj, prop);
type Values<T> = T[keyof T]
const withMap = <
Key extends PropertyKey,
Klass extends new () => any,
ClassMap extends Record<Key, Klass>
>(classMap: ClassMap) => {
function foo<Role extends PropertyKey>(role: Role): Role extends keyof ClassMap ? ClassMap[Role] : Values<ClassMap> | null
function foo<Role extends PropertyKey>(role: Role): Values<ClassMap> | null {
const storageUserType = localStorage.getItem('any item you want');
if (hasProperty(classMap, storageUserType)) {
return classMap[storageUserType]
}
return null;
}
return foo
}
const getUserType = withMap(ClassMap)
const foo = (str: string) => {
const userType = getUserType(str); // EmpSupport
if (userType) {
const result = new userType()
}
}
const result = getUserType('EmpSupport') // typeof EmpSupport
Playground 2