首页 > 解决方案 > 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;
    }
  }

标签: typescriptclass

解决方案


首先,我们需要知道它typeof UserType UserType两种不同的类型。

typeof UserType一种类型是类构造函数的类型。第二种类型UserTypeUserType类实例的类型。

在这种情况下,我认为最好使用 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');

如果要创建GetUserTyperetuen 值的实例,则需要使用额外的括号

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

游乐场 2


推荐阅读