How to set ability conditions using TypeScript

754 Views Asked by At

I am following CASL's cookbook on roles with predefined permissions. I have defined my PlatformAbility as follows, in line with the cookbook instructions.

import { Ability, AbilityClass, ForcedSubject } from '@casl/ability';

const platformBaseActions = ['manage', 'read', 'write'] as const;
const platformSubjects = [
  'all',
  'membership',
  'work-order',
  'equipment',
  'user',
] as const;

type PlatformAbilities = [
  typeof platformBaseActions[number],
  (
    | typeof platformSubjects[number]
    | ForcedSubject<Exclude<typeof platformSubjects[number], 'all'>>
  ),
];
export type PlatformAbility = Ability<PlatformAbilities>;
export const PlatformAbility = Ability as AbilityClass<PlatformAbility>;

Setting up role's permissions also works well.

import { AbilityBuilder } from '@casl/ability';

import { MembershipForUserDto } from '@my-org/shared/dtos-user-mgmt';

import { PlatformAbility } from './platform-ability';
import { PlatformRole } from './platform-role';

type PermissionsSetter = (
  membership: MembershipForUserDto,
  builder: AbilityBuilder<PlatformAbility>,
) => void;
export const platformRolePermissions: Record<PlatformRole, PermissionsSetter> =
  {
    PLATFORM_ADMIN(_, { can }) {
      can('manage', 'all');
    },
    DISTRIBUTOR_ADMIN({ distributorId }, { can }) {
      // can('read', 'membership', { distributorId: { $eq: '' } });
      // can('read', 'membership', { distributorId });
      can('write', 'membership');
    },
    DISTRIBUTOR_USER({ distributorId }, { can }) {
      can('read', 'work-order');
      can('read', 'equipment');
    },
  };

However, the moment I try to set a condition on one of the permissions (one of the commented out lines above), I get the following typing errors, respectively. The first error is on the entire line (can(...);) and the second only on distributorId.

No overload matches this call.
  Overload 1 of 2, '(action: "manage" | "read" | "write" | ("manage" | "read" | "write")[], subject: "membership" | "membership"[], conditions?: MongoQuery<never> | undefined): RuleBuilder<...>', gave the following error.
    Type 'string' is not assignable to type 'undefined'.
  Overload 2 of 2, '(action: "manage" | "read" | "write" | ("manage" | "read" | "write")[], subject: "membership" | "membership"[], fields?: string | string[] | undefined, conditions?: MongoQuery<never> | undefined): RuleBuilder<...>', gave the following error.
    Argument of type '{ distributorId: { $eq: string; }; }' is not assignable to parameter of type 'string | string[] | undefined'.
      Object literal may only specify known properties, and 'distributorId' does not exist in type 'string[]'.ts(2769)
(property) distributorId: string
No overload matches this call.
  Overload 1 of 2, '(action: "manage" | "read" | "write" | ("manage" | "read" | "write")[], subject: "membership" | "membership"[], conditions?: MongoQuery<never> | undefined): RuleBuilder<...>', gave the following error.
    Type 'string' is not assignable to type 'Pick<MongoQueryOperators<MergeUnion<never, string | number | symbol>>, "$eq" | "$ne" | "$lt" | "$lte" | "$gt" | "$gte" | "$in" | "$nin" | ... 5 more ... | "$exists"> | OperatorValues<...> | undefined'.
  Overload 2 of 2, '(action: "manage" | "read" | "write" | ("manage" | "read" | "write")[], subject: "membership" | "membership"[], fields?: string | string[] | undefined, conditions?: MongoQuery<never> | undefined): RuleBuilder<...>', gave the following error.
    Argument of type '{ distributorId: string; }' is not assignable to parameter of type 'string | string[] | undefined'.
      Object literal may only specify known properties, and 'distributorId' does not exist in type 'string[]'.ts(2769)

I am not sure if this is a bug or if I did something wrong with my typing. I've double and triple-checked my setup and I don't see where I diverged from the instructions in the cookbook. I tried explicitly setting the second Ability type parameter (Ability<PlatformAbilities, MongoQuery> and Ability<PlatformAbilities, MongoQuery<any>>) and I still get the same typing errors.

0

There are 0 best solutions below