[英]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.