You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何定义可逐层收窄的嵌套Record类型以构建权限对象?

如何为权限集合定义精确的嵌套对象类型

背景与现有代码

我有一组权限字符串集合,以及对应的类型工具:

const stringVals = [
  'create:user',
  'update:user',
  'delete:user',
  'create:document',
  'update:document',
  'delete:document',
  'delete:workflow',
  'run:workflow',
] as const

type StringVals = typeof stringVals[number]
type PermissionVerb<T extends string> = T extends `${infer Action}:${string}` ? Action : never
type PermissionKey<T extends string, V extends PermissionVerb<T>> = T extends `${V}:${infer Key}` ? Key : never

这些类型工具可以正确提取权限动作(Verb)和对应的资源键(Key):

  • type Verbs = PermissionVerb<StringVals> → 'create' | 'update' | 'delete' | 'run'
  • type CreateKeys = PermissionKey<StringVals, 'create'> → 'user' | 'document'
  • type RunKeys = PermissionKey<StringVals, 'run'> → 'workflow'

预期目标

我需要定义一个嵌套对象类型,结构如下:

{
  create: {
    user: true,
    document: true
  },
  update: {
    user: true,
    document: true
  },
  delete: {
    user: true,
    document: true,
    workflow: true,
  },
  run: {
    workflow: true,
  }
}

当前问题

我最初定义的类型无法精确约束内层对象的键:

type PermissionsObject<T extends string> = Record<PermissionVerb<T>, Record<PermissionKey<T, PermissionVerb<T>>, boolean>>

function createPermissionsObject<T extends string>(permissions: Readonly<T[]>): PermissionsObject<T> {
  throw 'not implemented'
}

这里的问题是,外层Record的每个动词对应的内层对象会包含所有可能的权限键,而非仅该动词对应的键。比如permissions.run.user不会触发类型错误,不符合预期。

解决方案

使用映射类型替代Record,为每个动词单独生成对应的资源键集合:

// 精确的嵌套权限对象类型
type PermissionsObject<T extends string> = {
  [Verb in PermissionVerb<T>]: Record<PermissionKey<T, Verb>, boolean>
}

这个类型会遍历每个权限动词,为其生成仅包含对应资源键的内层对象。比如run对应的内层对象只会包含workflow键,访问不存在的键会立即触发类型错误。

配套的实现函数

可以实现一个类型安全的函数来生成该对象:

function createPermissionsObject<T extends string>(permissions: Readonly<T[]>): PermissionsObject<T> {
  const result: Partial<PermissionsObject<T>> = {}
  
  permissions.forEach(perm => {
    const [verb, key] = perm.split(':') as [PermissionVerb<T>, PermissionKey<T, PermissionVerb<T>>]
    if (!result[verb]) {
      result[verb] = {} as Record<PermissionKey<T, typeof verb>, boolean>
    }
    result[verb][key] = true
  })
  
  return result as PermissionsObject<T>
}

// 使用示例
const permissions = createPermissionsObject(stringVals)
permissions.run.workflow // ✅ 类型正确
permissions.run.user     // ❌ 类型错误,符合预期

内容的提问来源于stack exchange,提问作者stackoverfloweth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 19:35:25