簡體   English   中英

解構泛型類型

[英]Destructuring a generic type

我有一個 function ,其中一些輸入的屬性取決於其道具之一的值。 所以我定義了一個類型如下,它按預期工作:

enum OrganizationPermission {
    UPDATE = 'organization:update',
    INVITE = 'organization:invite',
}

enum WorkspacePermission {
    UPDATE = 'workspace:update',
    INVITE = 'workspace:invite',
}

enum OrganizationRole {
    MANAGER = 'manager'
}

enum WorkspaceRole {
    MANAGER = 'manager'
}

type RolePermission = {
    [OrganizationPermission.UPDATE]: {
        organizationRole: OrganizationRole,
    },
    [OrganizationPermission.INVITE]: {
        organizationRole: OrganizationRole,
    },
    [WorkspacePermission.UPDATE]: {
        workspaceRole: WorkspaceRole,
    },
}

type Permissions = WorkspacePermission | OrganizationPermission;

type CheckPermissionsArgs<P extends Permissions> = {
    perform: P,
    sustain?: boolean,
} & (P extends keyof RolePermission ? RolePermission[P] : Record<string, never>);

function checkPermissions<P extends Permissions>(props: CheckPermissionsArgs<P>): void {
    // omitted for brevity
}

當我必須擴展此道具時會出現問題,如下例所示:

type CheckRolePermissionsArgs<P extends Permissions> = CheckPermissionsArgs<P> & {
    role: string[],
}

function checkRolePermissions<P extends Permissions>({role, ...props}: CheckRolePermissionsArgs<P>): void {
    // Typing error
    checkPermissions(props);
}

Typescript 抱怨說:

TS2345:'Pick<CheckRolePermissionsArgs 類型的參數

, “執行” | “維持” | Exclude<keyof (P extends OrganizationPermission | WorkspacePermission.UPDATE?RolePermission[P]: Record<...>), "role">>' 不可分配給“CheckPermissionsArgs<CheckRolePermissionsArgs”類型的參數

[“執行”]>'。 鍵入'Pick<CheckRolePermissionsArgs

, “執行” | “維持” | Exclude<keyof (P extends OrganizationPermission | WorkspacePermission.UPDATE?RolePermission[P]: Record<...>), "role">>' 不可分配給類型 'CheckRolePermissionsArgs

["perform"] 擴展 OrganizationPermission | WorkspacePermission.UPDATE? RolePermission[CheckRolePermissionsArgs<...>["perform"]]: Record<...>'

如何重構這些類型以避免在第二個示例中強制轉換props參數?

我認為這是因為逆變,但這只是我的猜測。 隨意批評我。

看到這個答案。

考慮下一個例子:


/**
 * VARIANCE
 */
declare var y: Omit<CheckRolePermissionsArgs<WorkspacePermission.UPDATE>, 'role'>

let x: CheckPermissionsArgs<WorkspacePermission.UPDATE> = y // ok
y = x // ok
checkPermissions(x)

因為, checkRolePermissions是高階 function:

function checkRolePermissions<P extends Permissions_>(props: CheckRolePermissionsArgs<P>): void {
  // Typing error
  const { role, ...rest } = props
  type Keys = keyof typeof rest // "perform" | "sustain" | Exclude<keyof (P extends keyof RolePermission ? RolePermission[P] : Record<string, never>), "role">
  checkPermissions(rest);
}

TS 無法確定rest類型,因為它在這個地方有點動態類型。 它僅在運行時已知。

我認為這里最好的解決方案是拆分CheckPermissionsArgs類型。

enum OrganizationPermission {
  UPDATE = 'organization:update',
  INVITE = 'organization:invite',

}

enum WorkspacePermission {
  UPDATE = 'workspace:update',
  INVITE = 'workspace:invite',
}


enum OrganizationRole {
  MANAGER = 'manager'
}

enum WorkspaceRole {
  MANAGER = 'manager'
}

type RolePermission = {
  [OrganizationPermission.UPDATE]: {
    organizationRole: OrganizationRole,
  },
  [OrganizationPermission.INVITE]: {
    organizationRole: OrganizationRole,
  },
  [WorkspacePermission.UPDATE]: {
    workspaceRole: WorkspaceRole,
  }
}

type Permissions_ = WorkspacePermission | OrganizationPermission;


type CheckPermissionsArgs<P extends Permissions_> = {
  perform: P,
  sustain?: boolean,
};

type Union<P extends Permissions_> = P extends keyof RolePermission ? RolePermission[P] : Record<string, never>

function checkPermissions<P extends Permissions_>(props: CheckPermissionsArgs<P>, data: Union<P>) {
  // this object has exactly the same type as you have in your question
  const merged = { ...props, ...data } 
}


type CheckRolePermissionsArgs<P extends Permissions_> = CheckPermissionsArgs<P> & {
  role: string[],
}



function checkRolePermissions<P extends Permissions_>({ role, ...rest }: CheckRolePermissionsArgs<P>) {
  // Now, TS is able to infer the type
  return (data: Union<P>) => checkPermissions(rest, data);

}


checkRolePermissions({
  perform: OrganizationPermission.UPDATE,
  sustain: true,
  role: ['sdf']
})({
  organizationRole: OrganizationRole.MANAGER,
}) // ok


checkRolePermissions({
  perform: WorkspacePermission.INVITE,
  sustain: true,
  role: ['sdf']
})({
  organizationRole: OrganizationRole.MANAGER,
}) // expected error


操場

暫無
暫無

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

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