Repository: strapi/strapi
File: packages/core/admin/admin/src/core/apis/Widgets.ts (TypeScript)

Code before:
type Widget = Omit<WidgetArgs, 'id' | 'pluginId'> & { uid: WidgetUID };

type DescriptionReducer<T extends object> = (prev: Widget[]) => (T | Widget)[];

class Widgets {
  widgets: Widget[];

  constructor() {
    this.widgets = [];
  }

  private generateUid = (widget: WidgetArgs | Widget): WidgetUID => {
    if ('uid' in widget && widget.uid) {
      return widget.uid;
    }

    // At this point, widget must be WidgetArgs (has id and pluginId)
    const widgetArgs = widget as WidgetArgs;
    return (
      widgetArgs.pluginId
        ? `plugin::${widgetArgs.pluginId}.${widgetArgs.id}`
        : `global::${widgetArgs.id}`
    ) as WidgetUID;
  };

  private addUidToWidgets = (widgets: (WidgetArgs | Widget)[]): Widget[] =>
    widgets.map((widget) => {
      // If widget already has uid, it's already a Widget
      if ('uid' in widget && widget.uid) {
        return widget as Widget;
      }

      // Otherwise, it's a WidgetArgs
      const widgetArgs = widget as WidgetArgs;
      invariant(widgetArgs.id, 'An id must be provided');
      invariant(widgetArgs.component, 'A component must be provided');
      invariant(widgetArgs.title, 'A title must be provided');
      invariant(widgetArgs.icon, 'An icon must be provided');

      const { id, pluginId, ...widgetWithoutId } = widgetArgs;
      return {
        ...widgetWithoutId,
        uid: this.generateUid(widgetArgs),
      };
    });

  register(widgets: WidgetArgs): void;
  register(widgets: WidgetArgs[]): void;
  register(widgets: DescriptionReducer<WidgetArgs>): void;
  register(widgets: WidgetArgs | WidgetArgs[] | DescriptionReducer<WidgetArgs>) {
    if (Array.isArray(widgets)) {

Review comment (suggestion):
The logic and types would all be simpler if you generated the UID dynamically on getAll() instead of on registration

Code after:
type WidgetWithUID = Omit<WidgetArgs, 'id' | 'pluginId'> & { uid: WidgetUID };

type DescriptionReducer = (prev: WidgetArgs[]) => WidgetArgs[];

class Widgets {
  widgets: WidgetArgs[];

  constructor() {
    this.widgets = [];
  }

  private generateUid = (widget: WidgetArgs): WidgetUID => {
    return widget.pluginId ? `plugin::${widget.pluginId}.${widget.id}` : `global::${widget.id}`;
  };

  private checkWidgets = (widgets: WidgetArgs[]): void => {
    widgets.forEach((widget) => {
      invariant(widget.id, 'An id must be provided');
      invariant(widget.component, 'A component must be provided');
      invariant(widget.title, 'A title must be provided');
      invariant(widget.icon, 'An icon must be provided');
    });
  };

  register(widgets: WidgetArgs | WidgetArgs[] | DescriptionReducer) {
    if (Array.isArray(widgets)) {
      this.checkWidgets(widgets);
      this.widgets = [...this.widgets, ...widgets];
    } else if (typeof widgets === 'function') {
      const newWidgets = widgets(this.widgets);
      this.checkWidgets(newWidgets);
      this.widgets = newWidgets;
    } else if (typeof widgets === 'object') {
      this.checkWidgets([widgets]);
      this.widgets.push(widgets);
    } else {
      throw new Error('Expected widgets to be an array or a reducer function');
    }
  }

  getAll = (): WidgetWithUID[] => {
    return this.widgets.map((widget) => {
      const { id, pluginId, ...widgetBase } = widget;
      return {
        ...widgetBase,
        uid: this.generateUid(widget),
      };
    });
  };
}