能否反射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
相关产品推荐
相关产品推荐

