TypeScript后端Branch类优化:DRY原则落地与可复用自定义错误方案
优化方案:遵循DRY原则重构Branch类的验证与清理逻辑
一、合并自定义错误类为通用验证异常
将十几个独立的错误类替换为一个可配置的ValidationException,通过参数区分不同错误场景,既保留错误上下文清晰度,又减少冗余类文件:
// src/entities/Branch/exceptions/Validation.exception.ts export class ValidationException extends Error { constructor( public readonly field: string, public readonly rule: string, message: string ) { super(message); this.name = "ValidationException"; Object.setPrototypeOf(this, ValidationException.prototype); } }
原NameLengthCannotBeZeroException可替换为:
throw new ValidationException("name", "minLength", "分支名称不能为空");
二、提取通用清理方法
所有字符串类型字段的清理逻辑完全一致,提取为通用静态方法;针对数字类型单独处理:
// 通用字符串清理 private static sanitizeString(value: string): string { return value .split("\n")[0] .replace(/^[\r\t\f ]+|[\r\t\f ]+$/g, "") .replace(/[\t\f ]+/g, " "); } // 数字类型清理(处理streetNumber) private static sanitizeNumber(value: number | null): number | null { return value === null ? value : Math.floor(value); }
三、抽象通用验证规则
封装重复的验证逻辑为可复用函数,接收字段名、值和规则参数:
// 字符串长度验证(支持最小/最大长度) private static validateStringLength( field: string, value: string, min?: number, max?: number ): void { if (min !== undefined && value.length < min) { throw new ValidationException( field, "minLength", `${field}长度不能小于${min}` ); } if (max !== undefined && value.length > max) { throw new ValidationException( field, "maxLength", `${field}长度不能超过${max}` ); } } // 正整数验证(允许null) private static validatePositiveNumber( field: string, value: number | null ): void { if (value !== null && value <= 0) { throw new ValidationException( field, "positiveNumber", `${field}不能小于或等于0` ); } }
四、配置化批量处理字段
定义字段配置对象映射每个字段的清理/验证规则,通过循环批量处理,彻底消除重复方法:
// 字段配置类型定义 type FieldConfig<T> = { sanitize?: (value: T) => T; validate?: (field: string, value: T) => void; }; // Branch字段的验证与清理配置 private static readonly fieldConfigs: Record<keyof Branch, FieldConfig<any>> = { name: { sanitize: Branch.sanitizeString, validate: (field, value) => Branch.validateStringLength(field, value, 1, 200) }, streetAddress: { sanitize: Branch.sanitizeString, validate: (field, value) => Branch.validateStringLength(field, value, undefined, 50) }, streetNumber: { sanitize: Branch.sanitizeNumber, validate: Branch.validatePositiveNumber }, streetComplement: { sanitize: Branch.sanitizeString, validate: (field, value) => Branch.validateStringLength(field, value, undefined, 50) }, neighborhood: { sanitize: Branch.sanitizeString, validate: (field, value) => Branch.validateStringLength(field, value, undefined, 50) }, city: { sanitize: Branch.sanitizeString, validate: (field, value) => Branch.validateStringLength(field, value, undefined, 50) }, state: { sanitize: Branch.sanitizeString, validate: (field, value) => Branch.validateStringLength(field, value, undefined, 50) }, country: { sanitize: Branch.sanitizeString, validate: (field, value) => Branch.validateStringLength(field, value, undefined, 50) } }; // 通用字段处理方法 private static processField<T>(field: keyof Branch, value: T): T { const config = Branch.fieldConfigs[field]; if (!config) return value; const sanitizedValue = config.sanitize ? config.sanitize(value) : value; config.validate?.(field as string, sanitizedValue); return sanitizedValue; }
五、重构实例创建逻辑
添加工厂方法create,在实例化时自动执行所有字段的清理与验证:
static create(branchData: Omit<Branch, "id" | "createdAt" | "updatedAt">): Branch { const branch = new Branch(); // 处理需要验证的字段 branch.name = Branch.processField("name", branchData.name); branch.streetAddress = Branch.processField("streetAddress", branchData.streetAddress); branch.streetNumber = Branch.processField("streetNumber", branchData.streetNumber); branch.streetComplement = Branch.processField("streetComplement", branchData.streetComplement); branch.neighborhood = Branch.processField("neighborhood", branchData.neighborhood); branch.city = Branch.processField("city", branchData.city); branch.state = Branch.processField("state", branchData.state); branch.country = Branch.processField("country", branchData.country); // 赋值其他无需验证的字段 branch.active = branchData.active; branch.createdBy = branchData.createdBy; branch.createdFrom = branchData.createdFrom; branch.updatedBy = branchData.updatedBy; branch.updatedFrom = branchData.updatedFrom; branch.environment = branchData.environment; branch.reportLogo = branchData.reportLogo; branch.reportFinalMessage = branchData.reportFinalMessage; branch.cnpj = branchData.cnpj; branch.latitude = branchData.latitude; branch.longitude = branchData.longitude; branch.zipCode = branchData.zipCode; // 设置时间戳 const now = new Date(); branch.createdAt = now; branch.updatedAt = now; return branch; }
优化优势
- 彻底遵循DRY原则:消除大量重复的sanitize/validate方法,新增字段只需添加配置
- 错误类复用:用一个通用异常类替代十几个独立错误类,同时保留错误上下文
- 可维护性提升:验证规则集中管理,修改规则只需调整通用函数或配置
- 类型安全:通过TypeScript的
keyof和泛型保证字段处理的类型正确性
内容的提问来源于stack exchange,提问作者Cristofer
相关产品推荐
相关产品推荐

