question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Type safety of fields in conditions

See original GitHub issue

Hello,

I’ve just started using casl, so I might be doing (multiple) things wrong, but it seems that “can*” rules are not type safe.

When I define rules such as the one below, the fields I’m using to express the MongoDB query are using any, meaning that if I refactor my code, I might break the rules.

I’ve of course tested this code to alleviate this issue, but it would be awesome if casl could recognize the types and enforce type safety.

  • Casl version: 4.1.3

Example:

import { Ability, defineAbility, InferSubjects } from "@casl/ability";
import { UserRoleInMeetingV1 } from "../user-role-in-meeting-v1.intf";
import { MeetingStateV1 } from "../../../entities/meetings/meeting-state-v1.intf";
import { assertUnreachable } from "@didowi/common-utils";

export enum MeetingBaseActions {
  VIEW = "VIEW",
  EDIT_BASIC_INFO = "EDIT_BASIC_INFO",
  EDIT_STATE = "EDIT_STATE",
  REMOVE = "REMOVE",
}

export class MeetingBaseSubject {
  /**
   * Helps CASL to detect the subject type
   * Reference: https://stalniy.github.io/casl/v4/en/guide/subject-type-detection
   */
  static readonly modelName = "MeetingBaseSubject";

  constructor(readonly roles: UserRoleInMeetingV1[]) {}
}

/**
 * Subjects can either be the type (when defining a rule) or an object of that type (when checking)
 */
export type MeetingBaseSubjects = InferSubjects<typeof MeetingBaseSubject>;

/**
 * The ability is the combination of possible actions and subjects
 */
export type MeetingBaseAbility = Ability<[MeetingBaseActions, MeetingBaseSubjects]>;

/**
 * Define the abilities for base
 * @param meetingState the meeting state to define abilities for
 */
export function defineAbilitiesForMeetingBase(meetingState: Readonly<MeetingStateV1>): MeetingBaseAbility {
  return defineAbility((can) => {
    switch (meetingState) {
      case MeetingStateV1.DRAFT:
        can(MeetingBaseActions.VIEW, MeetingBaseSubject, { roles: { $in: [UserRoleInMeetingV1.OWNER] } });
        can(MeetingBaseActions.EDIT_BASIC_INFO, MeetingBaseSubject, { roles: { $in: [UserRoleInMeetingV1.OWNER] } });
        can(MeetingBaseActions.EDIT_STATE, MeetingBaseSubject, { roles: { $in: [UserRoleInMeetingV1.OWNER] } });
        can(MeetingBaseActions.REMOVE, MeetingBaseSubject, { roles: { $in: [UserRoleInMeetingV1.OWNER] } });
        break;
      case MeetingStateV1.DELETED:
        // Noone can do anything
        break;
      case MeetingStateV1.CANCELLED:
        can(MeetingBaseActions.VIEW, MeetingBaseSubject, {
          roles: {
            $in: [
              UserRoleInMeetingV1.OWNER,
              UserRoleInMeetingV1.CATEGORY_MEMBER,
              UserRoleInMeetingV1.PARTICIPANT,
              UserRoleInMeetingV1.TIMEKEEPER,
              UserRoleInMeetingV1.SCRIBE,
            ],
          },
        });
        break;
      case MeetingStateV1.PLANNED:
        can(MeetingBaseActions.VIEW, MeetingBaseSubject, {
          roles: {
            $in: [
              UserRoleInMeetingV1.OWNER,
              UserRoleInMeetingV1.CATEGORY_MEMBER,
              UserRoleInMeetingV1.PARTICIPANT,
              UserRoleInMeetingV1.TIMEKEEPER,
              UserRoleInMeetingV1.SCRIBE,
            ],
          },
        });
        can(MeetingBaseActions.EDIT_BASIC_INFO, MeetingBaseSubject, {
          roles: { $in: [UserRoleInMeetingV1.OWNER, UserRoleInMeetingV1.SCRIBE] },
        });
        can(MeetingBaseActions.EDIT_STATE, MeetingBaseSubject, {
          roles: { $in: [UserRoleInMeetingV1.OWNER, UserRoleInMeetingV1.SCRIBE, UserRoleInMeetingV1.TIMEKEEPER] },
        });
        break;
      default:
        assertUnreachable(meetingState);
    }
  });
}

By the way, I wanted to use the abilityBuilder to define those rules, but for some reason that eludes me, it never worked and I’m not too sure why. It was as if the subjects were not recoginized although I had the same base setup. I’m not sure I understand the docs about it…

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:31 (19 by maintainers)

github_iconTop GitHub Comments

1reaction
stalniycommented, Aug 25, 2020

Implemented in next branch and will be available in v5, including support for typesafe fields

1reaction
stalniycommented, Jul 20, 2020

Ok, now I know how it’s called 😃 The issue is that typescript doesn’t support Higher Kinded Types(HKT). There is an issue from 2014 - https://github.com/microsoft/TypeScript/issues/1213 which probably will never be fixed.

I’ll try to use https://github.com/strax/tshkt to emulate HKT. If this doesn’t work well for casl, then the only way is to create one type of AbilityBuilder per condition type (e.g., MongoAbilityBuilder, FunctionAbilityBuilder, JsonSchemaAbilityBuilder, etc) and use it as:

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

interface JsonSchemAbilityBuilder {
   can<S extends ...>(action: string, subject: S, conditions: JsonSchema<S>): RuleBuilder
   cannot(...)...
}

const JsonSchemAbilityBuilder = AbilityBuilder as AbilityBuilderClass<JsonSchemAbilityBuilder>;
Read more comments on GitHub >

github_iconTop Results From Across the Web

Field Hazards | Environmental Health & Safety - UCSB EHS
Use these tables of hazards, risks and control measures associated with field work to complete a field safety plan and decide on Go/No-Go...
Read more >
Safety Guidelines for Field Researchers
Possible Risks: Potentially hazardous plants, animals, terrain and weather conditions where you plan to work. Complete a “Field Research Safety Plan”. A simple ......
Read more >
Field Safety Guide - University of South Florida
Special risks related to travel, being outside, and interactions with strangers are inherent to field work.
Read more >
Types of Hazards | National Association of Safety Professionals
Safety hazards are the most common type of hazard in the workplace. They refer to unsafe conditions leading to illness, injury and even...
Read more >
Safety Guidelines for Field Researchers
I. General Field Safety Guidelines. ... informed of any allergies or other medical conditions of the field team ... close encounters of the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found