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

TypeScript中如何在基类方法签名中引用调用类类型

解决TypeScript基类中使用this类型实现通用修改方法的类型错误

我尝试利用TypeScript的this类型特性,在基类中实现一个通用的toModified方法,让子类继承后自动适配自身类型,避免重复代码。但基类中的实现出现了类型错误,子类重写后却能正常运行。

问题代码

type ClassProperties<C> = {
  [K in keyof C as C[K] extends Function ? never : K]: C[K]
}

abstract class BaseClass {

  clone() { return structuredClone(this); }

  toModified(change: Partial<ClassProperties<this>>) {
    const c = this.clone();
    type changetype = typeof change;
    type changekeys = keyof changetype;
    type changevals = changetype[changekeys];
    Object.entries(change).forEach(([k, v]: [changekeys, changevals]) => { (c[k] as changevals) = v; });
    return c;
  }
}

export class ConcreteClass extends BaseClass {
  constructor(public a: number, public b: string = "", public c: boolean = false) {
    super();
  }
}

错误信息

typescript [2345]: Argument of type '([k, v]: [keyof ClassProperties<this>, changevals]) => void' is not assignable to parameter of type '(value: [string, unknown], index: number, array: [string, unknown][]) => void'.

原因分析

在基类中,this是一个抽象的动态类型,TypeScript无法在编译阶段确定ClassProperties<this>的具体键类型。而Object.entries(change)返回的是[string, unknown][],导致回调函数的参数类型与预期不匹配。子类中明确指定了具体类名,TypeScript能确定属性键的具体类型,因此不会报错。

解决方案

方案一:调整类型断言

直接在遍历回调中对键和值做精确类型断言,让TypeScript识别类型兼容性:

type ClassProperties<C> = {
  [K in keyof C as C[K] extends Function ? never : K]: C[K]
}

abstract class BaseClass {

  clone() { return structuredClone(this); }

  toModified(change: Partial<ClassProperties<this>>) {
    const c = this.clone();
    Object.entries(change).forEach(([k, v]) => {
      const propKey = k as keyof ClassProperties<this>;
      c[propKey] = v as ClassProperties<this>[typeof propKey];
    });
    return c;
  }
}

export class ConcreteClass extends BaseClass {
  constructor(public a: number, public b: string = "", public c: boolean = false) {
    super();
  }
}

方案二:使用泛型约束this

通过泛型明确this的具体子类类型,提升类型检查的准确性:

type ClassProperties<C> = {
  [K in keyof C as C[K] extends Function ? never : K]: C[K]
}

abstract class BaseClass {

  clone() { return structuredClone(this); }

  toModified<T extends BaseClass>(this: T, change: Partial<ClassProperties<T>>): T {
    const c = this.clone() as T;
    Object.entries(change).forEach(([k, v]) => {
      const propKey = k as keyof ClassProperties<T>;
      c[propKey] = v as ClassProperties<T>[typeof propKey];
    });
    return c;
  }
}

export class ConcreteClass extends BaseClass {
  constructor(public a: number, public b: string = "", public c: boolean = false) {
    super();
  }
}

两种方案都能实现基类的通用性,子类无需重写toModified方法,同时保留类型安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 11:53:21