typescript - x instanceof 类类型通过参数传递
问题描述
我试图确定一个变量是否是函数中参数类型类的子类。这是为系统完成的,以确保使用基于角色的方法进行身份验证。
我有一个脚本,其中包含用户类型列表和分配类的工厂方法:
abstract class UserType {}
abstract class EmpRoleType extends UserType {}
abstract class ClientRoleType extends UserType {}
class EmpSupport extends EmpRoleType {}
class ClientSupport extends ClientRoleType {}
function getUserType(role: string): UserType | null {
switch(role) {
case 'EmpSupport':
return EmpSupport;
case 'ClientSupport':
return ClientSupport;
default:
return null;
}
}
要查找用户是否使用正确的角色进行身份验证,我有以下功能:
// Pass in parent type of role to allow. Eg. EmpRoleType
function allowPermission(allowParentRole: UserType, userRole: UserType) {
return userRole instanceof allowParentRole;
}
然而,这给了我一个错误:The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.
甚至尝试从getUserType
失败中实例化一个类:
const x = new getUserType('EmpSupport')();
错误:'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.
更新:
使用 Captain-yossarian 的回答:假设我不知道字符串的值,我如何找到将字符串变量映射到其中一个类?例如。
get UserType(): UserType | null {
let storageUserType = localStorage.getItem(AuthService.authStorageItems.userType);
if (!storageUserType) {
return null;
}
try {
return ClassMap[storageUserType]; // or
return GetUserType(storageUserType);
} catch (error) {
return null;
}
}
解决方案
首先,我们需要知道它typeof UserType
是 UserType
两种不同的类型。
第typeof UserType
一种类型是类构造函数的类型。第二种类型UserType
是UserType
类实例的类型。
在这种情况下,我认为最好使用 HashMap 数据结构而不是switch
. 考虑一下:
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;
在这种情况下,我们不再需要switch
了。现在我们可以定义getUserType
函数:
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;
};
};
现在我们定义变量以使用正确的映射访问该函数
const GetUserType = withMap(ClassMap);
现在我们可以通过将字符串传递给函数来获取类类型。
const userType = GetUserType('EmpSupport'); // typeof EmpSupport
注意:如果将键传递给函数,它将返回 null
例如。GetUserType('bad entry');
如果要创建GetUserType
retuen 值的实例,则需要使用额外的括号
const userType = new (GetUserType('EmpSupport'))(); // EmpSupport
allowPermission
应该是一个 typeguard,如下所示:
function allowParentPermission<Allowed extends typeof UserType>(
AllowParentRole: Allowed,
userRole: unknown
): userRole is InstanceType<Allowed> {
return userRole instanceof AllowParentRole;
}
按照惯例,所有类都应该大写,这就是为什么我写AllowParentRole
而不是allowParentRole
整个代码:
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;
}
更新
userRole is
- 是类型保护的特殊语法
更新 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
推荐阅读
- node.js - 在firebase云功能中查询firebase firestore?
- java - SecureRandom.ints() 安全吗?
- python - 名称错误未为类定义全局名称“类名”
- stripe-payments - 有用于下载收据的 Stripe API 吗?
- excel - 突出显示包含扩展列表中单词的单元格
- mysql - 如何从已截断的 Mysql 5.6 分区中清除数据?
- sap-cloud-sdk - 如何在 SCP multitanant 应用程序中获取订阅者的目的地
- vue.js - 使用 Koa 启动重定向后的 CORS 问题
- graph - 如何将二叉搜索树转换为列表
- javascript - 在下一页的控制台中展开 JavaScript 对象