TypeScript中如何创建兼顾强类型与灵活性的通用Model基类
实现方案
你可以通过泛型基类+局部类型断言的方式同时满足两个需求,既保留强类型校验,又不需要子类重复编写赋值逻辑。
前置类型定义
先统一全局用到的工具类型:
type Dictionary<T = any> = Record<string, T>;
第一步:改造Model基类
将基类改为泛型类,接收子类的字段类型作为泛型参数,set方法参数直接用泛型约束,赋值时仅做局部类型断言绕过索引检查:
export class Model<T extends Record<string, any>> { _required_fields: Array<string> = []; _optional_fields?: Array<string> = []; constructor(params: Partial<T> = {}) { // 原有必填字段校验逻辑保留 this.set(params); } set(params: Partial<T>){ // 原有字段合法性校验逻辑保留 this.all_fields.forEach(key => { // 仅此处做局部类型断言,不影响全局类型 (this as unknown as T)[key as keyof T] = params[key as keyof T]; }); } get all_fields(): Array<string> { return [...this._required_fields,...(this._optional_fields || [])]; } get required_fields() { return this._required_fields; } }
第二步:改造子类实现
子类继承时传入自身字段的接口类型,无需重写set方法即可复用所有基类逻辑:
// 先定义User类的字段类型 interface IUser { username: string; email?: string; } export class User extends Model<IUser> implements IUser { // 子类字段正常定义,点语法访问时会有完整类型提示 username: string = ''; email: string = ''; static REQUIRED_FIELDS: Array<keyof IUser> = ['username']; static OPTIONAL_FIELDS: Array<keyof IUser> = ['email']; get required_fields() { return this._required_fields.length === 0 ? User.REQUIRED_FIELDS : this._required_fields; } static get ALL_FIELDS() { return [...User.REQUIRED_FIELDS, ...User.OPTIONAL_FIELDS]; } constructor(params: Partial<IUser> = {}) { super(params); this._required_fields = User.REQUIRED_FIELDS; this._optional_fields = User.OPTIONAL_FIELDS; } }
效果验证
使用时完全保留TypeScript强类型特性:
- 点语法访问字段正常:
const user = new User({username: '张三'}); console.log(user.username)有完整类型提示 - set方法传参自动校验:
user.set({invalidField: '123'})会直接报TS类型错误,不允许传未定义的字段 - 所有校验、赋值逻辑全部收敛在基类,子类不需要重复编写相似代码
内容的提问来源于stack exchange,提问作者Peter Staab
相关产品推荐
相关产品推荐

