A typed permission matrix can map each role to the actions it can perform.

permission matrix Record types keep lookup keys and stored actions aligned with the domain model.

Permission Matrix Case

selectedRole
permissions.ts
Replay: real traced execution (multi-file project)
type Role = "viewer" | "editor" | "admin";
type Action = "read" | "write" | "delete";

const permissions: Record<Role, Action[]> = {
    viewer: ["read"],
    editor: ["read", "write"],
    admin: ["read", "write", "delete"]
};

function allowedActions(role: Role): string {
    return permissions[role].join(",");
}

const selectedRole: Role = "editor";
const actions: string = allowedActions(selectedRole);
const canDelete: boolean = permissions[selectedRole].includes("delete");

console.log(`role=${selectedRole};actions=${actions};delete=${canDelete}`);
type Role = "viewer" | "editor" | "admin";
type Action = "read" | "write" | "delete";

const permissions: Record<Role, Action[]> = {
    viewer: ["read"],
    editor: ["read", "write"],
    admin: ["read", "write", "delete"]
};

function allowedActions(role: Role): string {
    return permissions[role].join(",");
}

const selectedRole: Role = "viewer";
const actions: string = allowedActions(selectedRole);
const canDelete: boolean = permissions[selectedRole].includes("delete");

console.log(`role=${selectedRole};actions=${actions};delete=${canDelete}`);
  1. permissions ← [object Object], selectedRole ← editor

    1type Role = "viewer" | "editor" | "admin";2type Action = "read" | "write" | "delete";34const permissions→ [object Object]: Record<Role, Action[]> = {5    viewer: ["read"],6    editor: ["read", "write"],7    admin: ["read", "write", "delete"]8};910function allowedActions(role: Role): string {11    return permissions[role].join(",");12}1314const selectedRole→ editor: Role = "editor";  //@selectedRole="viewer"15const actions: string = allowedActions(selectedRoleeditor);16const canDelete: boolean = permissions[selectedRole].includes("delete");
  2. function allowedActions(role: Role): string

    7    admin: ["read", "write", "delete"]8};910function allowedActions(roleeditor: Role): string {11    return permissions[role]read,write.join(",");12}
  3. actions ← read,write, canDelete ← false

    14const selectedRole: Role = "editor";  //@selectedRole="viewer"15const actions→ read,write: string = allowedActions(selectedRoleeditor);16const canDelete→ false: boolean = permissions[selectedRole]read,write.includes("delete");1718console.log(`role=${selectedRoleeditor};actions=${actionsread,write};delete=${canDeletefalse}`);
    outputrole=editor;actions=read,write;delete=false
  1. permissions ← [object Object], selectedRole ← viewer

    1type Role = "viewer" | "editor" | "admin";2type Action = "read" | "write" | "delete";34const permissions→ [object Object]: Record<Role, Action[]> = {5    viewer: ["read"],6    editor: ["read", "write"],7    admin: ["read", "write", "delete"]8};910function allowedActions(role: Role): string {11    return permissions[role].join(",");12}1314const selectedRole→ viewer: Role = "viewer";15const actions: string = allowedActions(selectedRoleviewer);16const canDelete: boolean = permissions[selectedRole].includes("delete");
  2. function allowedActions(role: Role): string

    7    admin: ["read", "write", "delete"]8};910function allowedActions(roleviewer: Role): string {11    return permissions[role]read.join(",");12}
  3. actions ← read, canDelete ← false

    14const selectedRole: Role = "viewer";15const actions→ read: string = allowedActions(selectedRoleviewer);16const canDelete→ false: boolean = permissions[selectedRole]read.includes("delete");1718console.log(`role=${selectedRoleviewer};actions=${actionsread};delete=${canDeletefalse}`);
    outputrole=viewer;actions=read;delete=false