You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript父子类方法类型问题:自制迷你ORM编译报错求助

解决迷你ORM的TypeScript类型问题

核心问题分析

你遇到的类型错误根源在于实例方法create的this类型绑定错误,以及静态属性_pk的类型未与实例键名关联:

  1. 错误地将实例方法create的this约束为构造函数类型(typeof BaseModel),导致实例调用时类型不匹配(TS2684)。
  2. create方法中误将this当作构造函数,调用实例方法_getParams时触发类型错误(TS2339)。
  3. 静态属性_pk的类型为string,无法匹配Criteria要求的实例键名类型(TS2322)。

解决方案代码

修改BaseModel类

import { db } from '../db/db';

export interface Criteria<T> {
  field: Extract<keyof T, string>;
  value: T[Extract<keyof T, string>];
  comparison?: string;
}

// 泛型K指定主键键名,T指定实例类型
export class BaseModel<K extends string = 'id', T extends BaseModel<K> = BaseModel<K>> {
  static _pk: string = 'id';
  static _table: string = null;

  constructor(params: Partial<T>) {
    for (const key in params) {
      if (Object.prototype.hasOwnProperty.call(params, key)) {
        const fn = `${key}Process`;
        if (typeof this[fn] === 'function') {
          // @ts-ignore 可后续通过类型守卫优化
          this[fn](params[key]);
        } else {
          // @ts-ignore
          this[key] = params[key];
        }
      }
    }
  }

  // 实例方法:this指向当前实例
  create(): Promise<T> {
    const params = this._getParams();
    // 获取实例对应的构造函数,并约束其类型
    const Constructor = this.constructor as typeof BaseModel & {
      _table: string;
      _pk: K;
      findOne: (criteria: Criteria<T>[]) => Promise<T>;
    };
    return db
      .insertFromModel(Constructor._table, params)
      .then((id) => Constructor.findOne([{ 
        field: Constructor._pk as Extract<keyof T, string>,
        value: id as T[Extract<keyof T, string>]
      }]));
  }

  static findOne<T extends typeof BaseModel>(this: T, criteria: Criteria<InstanceType<T>>[]): Promise<InstanceType<T>> {
    return db.selectFromModel(this._table, criteria, true).then((row: object) => {
      return new this(row) as InstanceType<T>;
    });
  }

  _getParams(): Partial<T> {
    const params: Partial<T> = {};
    for (const key of Object.keys(this)) {
      if (['id', '_table', '_pk'].includes(key)) continue;
      // @ts-ignore
      params[key as keyof T] = this[key];
    }
    return params;
  }
}

修改User子类

import { BaseModel } from './BaseModel';

// 指定主键键名为'id',实例类型为User
export class User extends BaseModel<'id', User> {
  static _table = 'users';
  static _pk = 'id';

  id: number;
  email: string;
  password: string;

  constructor(props: { id?: number; email: string; password: string }) {
    super(props);
  }
}

关键修改说明

  1. 修正create方法的this类型:
    将create的this从构造函数类型改为实例本身,确保new User().create()调用时,this指向User实例,解决TS2684错误。

  2. 关联主键与实例键类型:
    通过泛型K指定主键键名,将Constructor._pk断言为Extract<keyof T, string>,使其符合Criteria的字段类型要求,解决TS2322错误。

  3. 类型安全优化:
    将构造函数参数改为Partial<T>、_getParams返回Partial<T>,让IDE能正确提示实例属性,提升类型安全性。

测试验证

调用代码现在可以正常编译并获得类型提示:

new User({ email: 'test@test.com', password: '123123' }).create().then((user) => {
  console.log(user.id); // 类型自动推导为number
  console.log(user.email); // 类型自动推导为string
});

内容的提问来源于stack exchange,提问作者kRicha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:35:32