【问题标题】:Nesting class structures gives compiler errors嵌套类结构会导致编译器错误
【发布时间】:2021-09-29 00:36:25
【问题描述】:

我有一个这样的类层次结构:

用户:

  • 角色:角色[]

角色:

  • 权限:权限

每个类都有一个构造函数,将 args 转换为其指定的类,例如 User 将角色转换为 Role 实例。 Role 将权限转换为 Permission 实例。

示例代码:

const user = new User({
        roles: [
            {role_name: 'admin', permissions: {'*': '*'}} 
        ]
    })

当我使用嵌套的权限对象为用户传递 JSON 时,我得到编译器错误,因为权限上有方法。 Property 'has' is missing in type '{ '*': string; }' but required in type 'Permission'.

如何避免这些问题?

编辑:

如何使 Roles 类接受作为对象的权限,以便它可以正确地将 JSON 强制转换为 Permission 类型?

// users.ts
export interface User extends BaseModel {
    createdAt?: string;
    updatedAt?: string;
    email?: string;
    username?: string;
    fullname?: string;
    microsoftId?: string;
    roles?: UserRole[];
}

export class User {
    constructor(props?: Partial<User>) {
        if(!props){
            props = {};
        }

        props.roles = props.roles?.map(role => new Role(role)) || [];
        
        Object.assign(this, props);
    }

    hasPermission(service: string, perm: PermissionType){
        for(let role of this.roles || []){
            const has = (role.permissions as Permission).has(service, perm);
            if(has){
                return has;
            }
        }

        return false;
    }
}

// roles.ts


export interface Permission {
    [key: string]: PermissionType[]|any;
}

export class Permission {
    constructor(props: Partial<Permission>){
        Object.assign(this, props);
    }

    has(service: keyof Permission, permName: PermissionType|undefined): boolean {
        //.....
    }
}
export interface Role extends BaseModel {
    createdAt?: string;
    updatedAt?: string;
    role_name?: string;
    description?: string;
    scopes?: string[];
    permissions: Permission;
}
export class Role {
    constructor(props?: Partial<Role>) {
        if(!props){
            props = {};
        }

        props.permissions = new Permission(props.permissions || {});
        
        if (!Array.isArray(props.scopes)) {
            props.scopes = [];
        }

        Object.assign(this, props);
    }
}

【问题讨论】:

  • 您定义了一个类Permission,它有一个has 方法。您的{ "*": "*" } 没有该方法,因此不是Permission
  • 嗨@SilvioMayolo - 我澄清了我的问题。我想在构造函数中允许普通对象 - 但将它们正确强制转换为正确的 Permission 类型。此数据源自服务器 REST 响应(作为 JSON),因此我需要强制它们添加/等方法。
  • 然后当你收到 JSON 数据时,将其转换为 Permission 对象

标签: typescript


【解决方案1】:

不要将接口命名为与类相同。您正在合并名称并创建一个坦率地相当尴尬的设置。为构造函数参数提供单独的接口。

export interface PlainPermission {
    [key: string]: PermissionType[]|any;
}

export class Permission implements PlainPermission {
    [key: string]: PermissionType[]|any;

    constructor(props: Partial<PlainPermission>){
        Object.assign(this, props);
    }

    has(service: keyof Permission, permName: PermissionType|undefined): boolean {
        //.....
    }
}

RoleUser 也是如此。然后你有一个明显的区别:PlainPermission 是你传递给构造函数的“普通”Javascript 对象,Permission 是附加了所有漂亮、方便的方法的东西。

当您定义一个接口和一个具有相同名称的类时,它们会合并以创建一个更大的类,Permission 被定义为“任何具有接口中的东西的东西 has 方法”,这不是你想要的。

您将不得不从类中的接口复制字段名称,但这是有道理的:接口是实现某些东西的承诺,而类是实际的实现。一个是合同,另一个做合同规定的工作。您可以使用implements PlainPermission 作为额外检查,以确保您正确实现了接口。

【讨论】:

  • 这是有道理的——尽管我将它们命名为相同的原因是 Permission 类会自动从接口获取所有属性。我不认为这在你的例子中得到体现。
  • 查看我的编辑。您将无法自动获取名称,但您可以使用 implements 验证它们是否正确。
  • 好的 - 很高兴知道。作为替代方案,拥有一个没有方法的PlainPermission 类(名称与接口相同)然后让Permission 类扩展这个PlainPermission 类是不是一个坏主意?
  • 这可能行得通。老实说,我觉得这很有趣,因为PlainPermission(您使用它的方式)旨在用作接口,因此从可读性的角度来看,将其声明为类有点尴尬。但在功能上,它可以满足您的需求。
  • 是的,我在打字稿的这方面苦苦挣扎了一段时间。我的目标是能够将纯对象数据传递到一个类中并获得分配的属性,而无需重复很多代码。在 2 个不同的地方维护这些道具会增加一些开销。所以使用接口消除了这一点,因为类构造函数可以接受普通对象。
猜你喜欢
  • 1970-01-01
  • 2020-08-19
  • 2015-01-11
  • 1970-01-01
  • 2016-03-23
  • 2020-10-12
  • 1970-01-01
  • 2021-05-17
  • 1970-01-01
相关资源
最近更新 更多