【NestJS】service, helper, util 的区别
如果这段逻辑跟业务规则、领域事件、数据一致性有关 → 写成service如果只是格式化、转换、计算、字符串处理、文件路径拼接、响应包装→ 写成helper(加 @Injectable(),方便以后加依赖)如果非常通用、无任何依赖、项目中多处使用 → 优先写成纯函数放到 common/utils/ 下。
·
在 NestJS 中,helper 和 service 都是 provider(@Injectable() 类),但它们在职责、语义、使用场景和设计意图上有明显区别。
官方文档只说“services, repositories, factories, and helpers 等都可以作为 provider”,但没有严格定义 helper 是什么——这其实是社区的惯用叫法。
下面用表格对比一下目前(2025-2026)社区最常见的理解和实践差异:
| 方面 | Service | Helper (或 Helper Service) | 纯静态工具类 / util 函数 |
|---|---|---|---|
| 主要职责 | 承载业务逻辑、领域逻辑、用例协调 | 提供技术性、格式化、转换、工具性质的辅助功能 | 非常通用的、无状态的纯函数式工具 |
| 是否有状态 | 经常有(依赖 repository、其他 service、缓存等) | 通常无状态(stateless),方法独立 | 完全无状态 |
| 业务相关性 | 强,跟当前领域/模块高度相关 | 弱 或 中,偏技术实现细节 | 极弱,几乎与业务无关 |
| 典型例子 | UserService、OrderProcessingService | StringFormatterHelper、DateTimeHelper、ExcelHelper | string.utils.ts、date.utils.ts 中的纯函数 |
| 是否需要依赖其他 provider | 经常需要(注入 repo、其他 service、config 等) | 偶尔需要(比如要注入 ConfigService 读配置) | 基本不需要 |
| 注入方式 | 几乎总是注入到 controller / 其他 service | 通常注入到 controller / service 中使用 | 直接 import 使用,不需要注入 |
| 测试难度 | 较高(要 mock 很多依赖) | 较低(依赖少或无依赖) | 最低(纯函数,容易单元测试) |
| 文件命名习惯 | xxx.service.ts | xxx.helper.ts 或 xxx-transform.service.ts | xxx.util.ts / xxx.helper.ts(不加 @Injectable) |
| 是否加 @Injectable() | 必须 | 推荐(尤其是要注入依赖时) | 不需要 |
| 放在哪里 | 通常跟模块同级:users/user.service.ts | 常放在 helpers/ 子目录,或直接跟 service 同级 | src/common/utils/ 或模块内 utils/ 子目录 |
| 社区共识命名 | 业务名 + Service | 功能名 + Helper / Transformer / Formatter / UtilService | 功能名 + util / helper(小写文件) |
快速判断题:这段逻辑应该写成 service 还是 helper?
- “根据用户角色返回不同的权限列表” → Service(业务规则)
- “把手机号统一转成 +86 开头的国际格式” → Helper
- “从数据库取用户 + 校验密码 + 生成 token + 记录登录日志” → Service
- “把实体对象转成 DTO,处理字段隐藏、日期格式化” → Helper(常见叫 ResponseMapperHelper 或 DtoTransformer)
- “判断两个日期是否在同一天(忽略时间)” → 可以是 Helper,也可以直接写成 util 函数
实际项目中最常见的几种叫法和折中方案
-
全 helper 化(很多中小项目这样写)
- 凡是 controller 里不适合放的独立逻辑 → xxx.helper.ts + @Injectable()
- 优点:统一,容易搜索,测试友好
-
分层更清晰(中大型项目常见)
- 真正的业务逻辑 → xxx.service.ts
- 数据映射/格式化/转换 → xxx.mapper.ts 或 xxx.transformer.service.ts
- 纯技术工具 → xxx.helper.ts 或直接 utils/ 目录下的纯函数
-
最偷懒但也最常见
直接都叫 xxx.service.ts,但起名时体现区别:- UserService
- UserPasswordService
- UserDtoMapperService
- StringUtilsService(很多人会这么写……)
总结一句话建议(2026 年社区主流折中做法)
- 如果这段逻辑跟业务规则、领域事件、数据一致性有关 → 写成 service
- 如果只是格式化、转换、计算、字符串处理、文件路径拼接、响应包装 → 写成 helper(加 @Injectable(),方便以后加依赖)
- 如果非常通用、无任何依赖、项目中多处使用 → 优先写成纯函数放到 common/utils/ 下
更多推荐
所有评论(0)