Skip to content

[base-controller] Implement utility type ControllerActionsMap for generating, storing, exposing internal action types #4583

@MajorLift

Description

@MajorLift

Motivation

  • Currently, we manually enumerate each individual internal action type definition in controller files, and then manually enumerate them again in the type union for internal actions (example). We should have a DRY-er way of doing this.
  • Most handlers for controller internal actions are simply public controller class methods bound to the controller instance.
  • Instead of exporting each action separately, we could export a single "controller actions map" type that contains all internal actions, and use it to select and extract any number of its stored action types.

Proof of concept

/**
 * A utility type that derives the public method names of a given messenger consumer class,
 * and uses it to generate the class's internal messenger action types.
 * @template Controller - A messenger consumer class.
 */
// TODO: Figure out generic constraint and move to base-controller
type ControllerActionsMap<Controller> = {
  [ClassMethod in keyof PublicInterface<Controller> as Controller[ClassMethod] extends ActionConstraint['handler']
    ? ClassMethod
    : never]: {
    type: `${typeof name}:${ClassMethod & string}`;
    handler: Controller[ClassMethod];
  };
};

type AssetsContractControllerActionsMap =
  ControllerActionsMap<AssetsContractController>;

/**
 * The union of all public class method names of {@link AssetsContractController}.
 */
type AssetsContractControllerMethodName =
  keyof AssetsContractControllerActionsMap;

/**
 * The union of all internal messenger actions available to the {@link AssetsContractControllerMessenger}.
 */
export type AssetsContractControllerActions =
  AssetsContractControllerActionsMap[AssetsContractControllerMethodName];

/* 
 * A single internal action type selected from the controller actions map
 */
export type AssetsContractControllerGetERC20StandardAction =
  AssetsContractControllerActionsMap['getERC20Standard'];

/**
 * A union of several internal types selected from the controller actions map
 */
export type AssetsContractControllerGetStandardActions = 
  AssetsContractControllerActionsMap['getERC20Standard' | 'getERC721Standard' | 'getERC1155Standard']

https://github.com/MetaMask/core/pull/4397/files#diff-7ada7b099f6bcc6f3d4acd71f94b604636abd22cc556a76dbe7b3e610b1d9233R90-R118

Acceptance Criteria

  • MVP: Write a generic type that...
    • a) Accepts a controller class.
    • b) Derives its public class method names.
    • c) Uses them to generate the class's internal messenger action types.
    • d) Outputs a type object populated with the action types.
    • e) The types are keyed with the de-namespaced action names (i.e. getERC20Standard instead of AssetsContractController:getERC20Standard).
  • Stretch: Better handling for exceptions.
    • a) Accepts a map of action names and handlers which are exceptions to the general rule that each class method corresponds to an action handler.
    • b) Add these exceptions to the controller actions map as well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestteam-wallet-frameworkDeprecated: Please use `team-core-platform` instead.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions