可以为参数类型推断嵌套对象的键吗?

时间:2020-08-27 21:42:54

标签: typescript

希望输入一个函数,但不能计算出一个参数。

我有多个对象,这些对象存储了允许的角色数组,然后通过它们的辅助功能的路径/屏幕在一个对象下命名。

该函数将获取屏幕上的键,然后再检查该特定权限对象下的哪个键:当前,使用以下功能时,keyof typeof getAuthPermissions | keyof typeof getUserPermissions的并集显然会返回所有键 checkUserPermission('user', '<all-keys>') 但是,我只想从传递给函数的任何屏幕推断出按键: 所有相关代码:

const userGroups = ['Manager', 'Reporting', 'Payments', 'Support'] as const;
type UserGroup = typeof userGroups[number];

const getUserPermissions = {
    userControls: ['Manager', 'Support', 'Payments'],
    wallet: ['Manager', 'Support']
};
const getAuthPermissions = {
    logoutUser: ['Manager'],
    extendUserBonus: ['Manager', 'Support']
}
// ... a fair few more.
const allPermissions = {
    user: getUserPermissions,
    auth: getAuthPermissions
    // ...
}
type Screens = keyof typeof allPermissions;

function checkUserPermission(
    screen: Screens,
    userRoles: UserGroup[],
    // this should be the keys for whichever screen was passed in, (eg. keyof typeof allPermissions[typeof screen]?)
    permissionToCheck: keyof typeof getAuthPermissions | keyof typeof getUserPermissions // returns ALL keys. want to infer just from screen passed in
): boolean {
    for (const role of userRoles) {
        if (allPermissions[screen][permissionToCheck].includes(role)) {
            return true;
        }
    }
    return false;
}

这可能吗?我知道获取嵌套键可能会非常棘手,但是我希望通过传递的参数推断这应该可行吗? 谢谢!

1 个答案:

答案 0 :(得分:2)

请注意,您的建议checkUserPermission<T extends Screens>(screen: T, permissionToCheck: keyof typeof allPermissions[T]) {}可以正常工作。

但是,您遇到类型错误,其中typescript不确定allPermissions[screen][permissionToCheck]这个表达式实际上是一个数组,尽管我认为它在理论上应该能够弄清楚。

如果您进行一些看起来很邪恶的打字,则可以使所有工作正常进行:

function checkUserPermission<T extends Screens>(
    screen: T,
    userRoles: UserGroup[],
    permissionToCheck: keyof typeof allPermissions[T] 
): boolean {

    for (const role of userRoles) {
        const roles = allPermissions[screen][permissionToCheck] as unknown as UserGroup[]
        if (roles.includes(role)) {
            return true;
        }
    }
    return false;
}

另一种选择:

以不同的方式定义getAuthPermissions和getUserPermissions,但是,这会失去某些类型的特异性,因此请谨慎使用:

const getUserPermissions: Record<string, UserGroup[]> = {
    userControls: ['Manager', 'Support', 'Payments'],
    wallet: ['Manager', 'Support'],
}

const getAuthPermissions: Record<string, UserGroup[]> = {
    logoutUser: ['Manager'],
    extendUserBonus: ['Manager', 'Support'],
}