ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

NgRx ESLint 插件 prefer-inline-action-props 规则详解:Action Props 使用内联类型而非接口

NgRx ESLint 插件 prefer-inline-action-props 规则详解:Action Props 使用内联类型而非接口 前端状态管理【免费下载链接】platformReactive State for Angular项目地址https://gitcode.com/gh_mirrors/pl/platform点击查看免费下载导读ngrx/eslint-plugin的prefer-inline-action-props规则suggestion 类型专门用于约束 NgRx Action 的 props 类型写法要求开发者在使用propsT()定义 Action 携带数据时直接使用内联的对象字面量类型而不是命名接口interface、类型别名type或类class。本指南将结合仓库源码说明该规则的设计动机、触发条件、自动修复建议的底层实现以及如何将其接入 ESLint 配置并在现有代码库中落地。规则概览prefer-inline-action-props是 modules/eslint-plugin/src/rules/store/prefer-inline-action-props.ts 中定义的 store 模块规则其核心元数据如下Type: suggestionFixable: No不提供自动修复仅提供 suggestions 建议Suggestion: Yes提供一键改写成内联类型的智能建议Requires type checking: No纯语法层静态检查无需类型检查器Configurable: No无可配置项schema 为空数组[]所属模块: store见规则meta.docs.ngrxModule: store规则通过createRule创建其 URL 生成器指向https://ngrx.io/guide/eslint-plugin/rules/${ruleName}即 modules/eslint-plugin/src/rule-creator.ts 中的约定。规则在 modules/eslint-plugin/src/rules/index.ts 中以prefer-inline-action-props的名称注册导出。规则动机为什么拒绝命名接口NgRx 代码库中存在大量携带数据的 Action而定义这些 Action 时必须给出 props 的类型。使用具名的接口或类型别名看似更整洁但在实际使用中会掩盖类型对开发者的意义。核心原因在于Action 的 props 本质上等同于函数的参数。调用方dispatch 该 Action 的开发者需要精确地知道需要提供什么形状、什么字段的数据内联类型能让这一信息直接呈现在调用点带来更好的 IDE 自动补全与类型提示体验。反之一个笼统命名的User接口往往需要开发者再点开定义才能确认其内部字段。规则文档同时提醒部分属性名不允许使用例如type。这是由 NgRx Action 本身的实现决定的——Action 对象上必须携带一个type字段来标识动作类型见下文源码佐证因此它不能作为 props 的一部分被重复定义。规则如何生效匹配模式与源码实现规则不需要类型检查其匹配完全基于语法选择器。核心选择器actionCreatorPropsComputed定义在 modules/eslint-plugin/src/utils/selectors/index.tsexport const actionCreatorProps ${actionCreator} CallExpression[callee.nameprops] as const; export const actionCreatorPropsComputed ${actionCreatorProps} TSTypeParameterInstantiation :matches(TSTypeReference[typeName.name!Readonly], [type/^TS(.*)(Keyword|Type)$/]) as const;它逐层匹配先找到createAction(...)调用表达式再定位其中直接子节点里的props(...)调用最后命中props尖括号类型参数中的类型引用节点——只要类型参数不是Readonly开头并且是以TS...Type或TS...Keyword命名的内置类型节点就会被报告。规则主体的实现见 prefer-inline-action-props.tscreate: (context) { return { actionCreatorPropsComputed { context.report({ node, messageId: preferInlineActionProps, suggest: [ { messageId: preferInlineActionPropsSuggest, fix: (fixer) [ fixer.insertTextBefore(node, {name: ), fixer.insertTextAfter(node, }), ], }, ], }); }, }; },规则上报两条消息preferInlineActionProps「Use inline types instead of interfaces, types or classes.」preferInlineActionPropsSuggest「Change to inline types.」值得注意的是建议suggest层面的修复它并非真正的自动修复Fixable: No而是利用fixer.insertTextBefore/fixer.insertTextAfter在原类型节点的前后分别插入{name:与}将propsPerson()建议改写为props{name: Person}()。这仅仅是在原类型外部包上一层{name: ...}说明该建议是一个基于语法的最小改写生成的属性名统一为name开发者仍需结合意图手动调整成真正的字段名因此规则被归类为 suggestion 而非 fixable。源码层面的佐证props 与 type 字段为什么 props 的内联类型如此重要且不能包含type可从 modules/store/src/action_creator.ts 的props函数实现看到端倪export function props P extends SafeProps, SafeProps NotAllowedInPropsCheckP, (): ActionCreatorPropsP { return { _as: props, _p: undefined! }; }propsP通过SafeProps约束对 P 做NotAllowedInPropsCheck检查配合 action_creator.ts 中defineType将type与props合并进最终的 Action 对象case props: return defineType(type, (props: object) ({ ...props, type, }));也就是说无论 props 里写什么最终的 Action 对象上都会被注入type字段。这正是type不允许出现在 props 中的底层原因它与框架自身注入的动作类型标识冲突。正确与错误示例对照原文档给出了清晰的对照以下结合测试用例补充更多变体。不正确的写法会被规则报告export interface User { id: number; fullName: string; } export const addUser createAction( [Users] Add User, propsUser() );只要propsX()中的X是一个命名类型引用接口、类型别名、类无论它是基础类型、泛型类型、数组还是复杂泛型组合都会触发本规则。测试用例modules/eslint-plugin/spec/rules/store/prefer-inline-action-props.spec.ts覆盖了以下全部违规形态// 基础类型 const notOk0 createAction(notOk0, propsnumber()); // 具名接口 const notOk1 createAction(notOk1, propsPerson()); // 带泛型参数的具名类型 const notOk2 createAction(notOk2, propsCustomerT()); // 只读数组 const notOk3 createAction(notOk3, propsReadonlyArrayTest()); // 数组简写 const notOk4 createAction(notOk4, propsTest[]());正确的写法规则放行export const addUser createAction( [Users] Add User, props{ id: number; fullName: string }() ); // 或者把复用类型作为对象的一个字段 export const addUser createAction( [Users] Add User, props{ user: User }() );对应的合法用例同样来自 spec 文件const ok0 createAction(ok0, props{ id: number, name: string }()); // Readonly 包装的嵌套对象类型 const ok1 createAction(ok1, propsReadonly{ description: string }()); // Readonly 与交叉类型组合 const ok2 createAction(ok2, propsReadonlyHttpErrorResponse { description: string }()); // 无 props 的纯动作 const ok3 createAction(ok3); // 具名类型作为对象字段而非直接作为 props const ok4 createAction([Users] Add User, props{ user: User }()); // 使用工厂函数而非 props 定义携带的数据 const ok5 createAction([API/User] Save user success, (user: Usernumber) ({ kind: SAVE_SUCCESS, message, user, }));从中可以提炼出三条合法的书写策略直接内联对象字面量类型props{ id: number; fullName: string }()复用具名类型时放进对象字段props{ user: User }()——User作为字段的类型出现在内联对象里类型引用点仍是内联对象本身因此不违规Readonly包裹的内联对象Readonly是选择器中唯一被显式豁免的类型名typeName.name!ReadonlypropsReadonly{ ... }()合法适合需要整体只读语义的场景使用构造型 Action Creator完全绕开props改用接收参数的函数定义 Action如ok5。通过测试用例验证规则行为规则的行为完全由 prefer-inline-action-props.spec.ts 中的ruleTester用例验证包含 6 个合法用例与 5 个违规用例。以违规用例notOk1为例code: const notOk1 createAction(notOk1, propsPerson()), errors: [ { messageId: preferInlineActionProps, suggestions: [ { messageId: preferInlineActionPropsSuggest, output: const notOk1 createAction(notOk1, props{name: Person}()), }, ], }, ],可见每个违规用例都会附带一条 suggestion其输出正是源码中insertTextBefore/insertTextAfter两个 fixer 拼接出的props{name: Person}()形态。这从测试侧印证了规则报告 建议双通道的行为模式。如何启用该规则该规则默认不开启需要显式配置。有两种方式方式一使用 NgRx 官方预设配置推荐规则已内置在 NgRx 官方配置中开启 preset 即可生效。查看 modules/eslint-plugin/src/configs/store.tsrules: { // ... ngrx/prefer-inline-action-props: error, // ... },这意味着使用ngrx的storepreset 时prefer-inline-action-props会被以error级别启用。同时在 modules/eslint-plugin/src/configs/all.ts 与 all-type-checked.ts 的all预设中同样收录了该规则。注意该规则requiresTypeChecking: false因此即便在未开启类型检查的all预设中也会生效不会因为引入该规则而额外带来类型检查开销。方式二在 eslint.config.mjs 中单独配置export default [ // ... 其余配置 { plugins: { ngrx: ngrxPlugin }, languageOptions: { parser: typescriptParser }, rules: { ngrx/prefer-inline-action-props: error, // 或 warn }, }, ];由于规则无可配置项severity 只能设置为error或warn或off。因其type: suggestion更适合先在warn级别观察一段时间的报告量再升级为error。实战建议与注意事项先在 warn 级别启用suggestion 类型规则通常带来较大代码改动建议先在 CI 或本地以warn观察报告分布再逐步收敛。善用编辑器里的 suggestionVS Code 等编辑器对suggest修复会显示为灯泡快捷操作。本规则的 suggestion 会把propsPerson()改成props{name: Person}()你需要手动把name改成实际字段名如{ user: Person }因此它只是起点不是终点。正确处理跨模块复用类型当多个 Action 共享同一形状的数据时推荐写成props{ user: User }()而不是让整个User直接作为 props 类型既保持复用又不违背本规则。注意type属性禁令props 类型中不能出现type字段这是由 action_creator.ts 中框架自动注入type字段的行为决定的。无类型检查的纯语法规则该规则适合无法或不想启用类型检查projectService等的轻量 CI 环境可直接基于 ESLint 语法分析运行。小结prefer-inline-action-props用一条语法级、无类型检查、无配置项的规则推动 NgRx 开发者把 Action props 写成所见即所得的内联类型从而提升 dispatch 调用处的类型可读性与 IDE 体验。它通过精确的 AST 选择器命中propsT()中的具名类型引用并以 suggestion 形式给出{name: T}的改写方向仓库中的 源码实现、选择器定义、测试用例 与 官方配置 共同构成了从规则到落地配置的完整闭环。赞分享前端状态管理【免费下载链接】platformReactive State for Angular项目地址https://gitcode.com/gh_mirrors/pl/platform点击查看免费下载相关推荐NgRx ESLint 规则指南prefer-action-creator-in-dispatch 强制使用 Action Creator 派发动作NgRx ESLint 规则指南prefer action creator in dispatch 强制使用 Action Creator 派发动作 导读 p前端状态管理Zola 主题实战基于 Portio-Zola 搭建极简作品集与多语言博客站点Zola 主题实战基于 Portio Zola 搭建极简作品集与多语言博客站点 Portio Zola 是一款以极简、排版精良、高度可定制为设计理念的 Z前端状态管理NgRx ESLint 插件 good-action-hygiene 规则深度解析以 [Source] Event 命名让 Action 成为唯一事件NgRx ESLint 插件 good action hygiene 规则深度解析以 Source Event 命名让 Action 成为唯一事件 本篇指南围前端状态管理上一篇深入解析 Tree-sitter 贡献指南从环境搭建、测试调试到版本发布全流程下一篇ebpf-go 贡献指南从 DCO 签署、特权测试到 testdata 再生成的完整实操流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表