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

如何在TypeScript类成员函数中使用过滤后的keyof this?

问题描述

需求:

  • 实现一个包含若干成员字段与函数的类
  • 类提供callMe函数,参数仅限该类的非函数成员字段名称,需排除成员函数名称

异常情况:

  • 使用类实例调用callMe时,类型检查符合预期
  • 在类的成员函数内部调用callMe时,出现类型错误

原代码:

// 我想用这个`Filter`获取类型的所有非函数字段名称
type Filter<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] & string;

class BaseClass {
  // 此函数仅接受匹配非函数成员名称的参数
  public callMe<V extends Filter<this>>(param: V) {}
}

class MyClass extends BaseClass {
  // 这些成员字段应被纳入范围
  public stringField: string = '';
  public numberField: number = 0;
  public booleanField: boolean = false;
  // 这些成员函数应被排除
  public shouldBeExclude() {}
  public test() {
    // 此行报错:
    // TS2345: Argument of type string is not assignable to parameter of type Filter<this>
    // Type 'string' is not assignable to type 'this[keyof this] extends Function ? never : keyof this'
    this.callMe('stringField');
  }
}

const instance = new MyClass();
// 但以下调用符合预期
instance.callMe('stringField'); // 合法
instance.callMe('numberField'); // 合法
instance.callMe('shouldBeExclude'); // 不合法: TS2345: Argument of type 'shouldBeExclude' is not assignable to parameter of type Filter<MyClass>
解决方法

问题根源在于类成员函数中的this是多态this类型,TypeScript无法在编译时确定它的具体类型(可能是当前类或其子类),导致Filter<this>无法正确解析为具体的字段名称集合。

通过给callMe添加this: T类型约束,让TypeScript推断出当前实例的具体类型T,从而正确解析Filter<T>:

type Filter<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] & string;

class BaseClass {
  // 添加this: T约束,让TypeScript推断具体的实例类型
  public callMe<T extends this>(this: T, param: Filter<T>) {}
}

class MyClass extends BaseClass {
  public stringField: string = '';
  public numberField: number = 0;
  public booleanField: boolean = false;
  public shouldBeExclude() {}
  public test() {
    this.callMe('stringField'); // 现在不再报错
  }
}

const instance = new MyClass();
instance.callMe('stringField'); // 合法
instance.callMe('numberField'); // 合法
instance.callMe('shouldBeExclude'); // 不合法,符合预期

另外,也可以使用TypeScript 4.1+的映射类型过滤语法简化Filter定义,效果一致:

// 简化版Filter类型
type Filter<T> = keyof {
  [K in keyof T as T[K] extends Function ? never : K]: T[K]
};

class BaseClass {
  public callMe<T extends this>(this: T, param: Filter<T>) {}
}
说明

添加this: T参数后,callMe的this会被推断为当前调用的具体实例类型(如MyClass),而非模糊的多态类型。此时Filter<T>能准确提取该类型的非函数成员名称,既保证了类型安全,又解决了成员函数内部调用的类型错误问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 03:00:07