You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否反射NgRx Action的Payload?Angular通用库开发技术问询

如何获取NgRx Action的props类型信息以生成动态输入界面

当然可行,但因为TypeScript的类型系统在运行时会被完全擦除,直接反射createAction返回的函数拿不到props<{members: IMember[]}>里的类型细节。得通过注入运行时元数据的方式解决,下面是两种实用方案:

方案一:包装createAction,手动附加元数据

写一个简单的包装函数,在创建Action时让开发者显式传入props的结构信息,把这些信息存在ActionCreator的自定义属性里:

import { createAction, props, ActionCreator } from '@ngrx/store';

// 定义元数据结构,按需扩展
interface ActionPropsMeta {
  [propName: string]: string; // 比如字段名: 类型标识,如 "members": "IMember[]"
}

// 包装createAction,添加元数据
export function createActionWithMeta<T>(
  type: string,
  meta: ActionPropsMeta
): ActionCreator<string, (props: T) => { type: string } & T> {
  const action = createAction(type, props<T>());
  // 把元数据挂载到ActionCreator上
  (action as any).__propsMeta = meta;
  return action;
}

// 使用示例
export const membersLoaded = createActionWithMeta<{members: IMember[]}>(
  '[MemberEffects] Members Loaded',
  { members: 'IMember[]' }
);

方案二:给现有Action追加元数据

如果不想修改Action的创建方式,可以用工具函数给已有的ActionCreator添加元数据:

import { ActionCreator } from '@ngrx/store';

interface ActionPropsMeta {
  [propName: string]: string;
}

export function attachActionPropsMeta<T>(
  action: ActionCreator<string, (props: T) => { type: string } & T>,
  meta: ActionPropsMeta
) {
  (action as any).__propsMeta = meta;
  return action;
}

// 使用示例
export const membersLoaded = attachActionPropsMeta(
  createAction('[MemberEffects] Members Loaded', props<{members: IMember[]}>()),
  { members: 'IMember[]' }
);

处理复杂类型(比如IMember数组)

如果需要生成IMember对象的输入界面,别用TypeScript接口(运行时不存在),改用类并附加静态元数据:

export class IMember {
  id: number;
  name: string;

  // 静态元数据,描述类的字段类型
  static propsMeta = {
    id: 'number',
    name: 'string'
  };
}

这样在通用库中,读取到members: 'IMember[]'时,就可以通过IMember.propsMeta获取字段信息,递归生成对应的输入组件。

通用库中读取元数据生成界面

在你的库中,遍历传入的Action数组时,取出每个Action的__propsMeta属性,根据元数据动态渲染输入控件:

function renderActionInputs(actions: any[]) {
  actions.forEach(action => {
    const meta = action.__propsMeta;
    if (!meta) return;

    // 根据meta生成对应的输入组件
    Object.entries(meta).forEach(([propName, type]) => {
      if (type.endsWith('[]')) {
        // 生成数组输入组件,比如重复的表单组
        const itemType = type.slice(0, -2);
        // 若itemType是类,读取其静态元数据生成子组件
      } else {
        // 生成基础类型输入组件(输入框、下拉框等)
      }
    });
  });
}

内容的提问来源于stack exchange,提问作者Tim Hardy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 06:10:37