簡體   English   中英

定義一個嵌套的 Record 類型,當你遍歷時它會變窄

[英]Define a nested Record type that narrows as you traverse

我的系統具有定義為字符串 [] 的權限,如下所示

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

這對諸如此類的事情非常有用

type Verbs = PermissionVerbs<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'
}

問題是第一個記錄不會縮小內部記錄。 所以run的外部對象鍵返回所有內容,而不僅僅是我想要的workflow

const permissions = createPermissionsObject(stringVals)
permissions.run.user // expect error

打字稿游樂場

我們必須使用映射類型,以便每個鍵K都可以用來計算其對應的類型。

type PermissionsObject<T extends string> = {
  [K in PermissionVerb<T>]: 
    Extract<T, `${K}${string}`> extends `${string}:${infer Key}`
      ? Record<Key, boolean>
      : never
}

K可以與Extract一起使用以從T獲取完整路徑,其中KAction 我們現在可以從這個結果中inferKey並在Record<Key, boolean>中使用它。

const permissions = createPermissionsObject(stringVals)
permissions.run.workflow
permissions.create.user

permissions.run.user
//              ^^^^ Property 'user' does not exist on type 
//                   'Record<"workflow", boolean>'

操場


獎金:

幾個字符更短但結果相同。

type PermissionsObject<T extends string> = {
  [K in T as PermissionVerb<K>]: 
    [K] extends [`${string}:${infer Key}`]
      ? Record<Key, boolean>
      : never
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM