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

TypeScript动态访问类属性及matches方法的合适类型选型

类属性子集匹配函数实现方案

动态访问实例属性

直接通过对象键索引就能实现动态访问,结合TypeScript泛型约束可保证类型安全:

class Base {
  id: number;
  name: string;
  age: number;

  constructor(id: number, name: string, age: number) {
    this.id = id;
    this.name = name;
    this.age = age;
  }

  matches<T extends keyof this>(params: Pick<this, T>): boolean {
    return Object.entries(params).every(([key, value]) => {
      // 断言键类型为实例属性键,避免类型报错
      return this[key as keyof typeof this] === value;
    });
  }
}

Object.entries返回的键是string类型,所以需要用key as keyof typeof this做类型断言,确保能合法访问实例属性。

替代Pick的类型选项

Pick本身就是为「选取对象属性子集」设计的类型,已经很贴合你的场景。如果需要更灵活的场景,可以考虑:

  • Partial:允许传入任意可选的属性子集,但不限制必须是指定的几个属性,适合宽松的匹配场景。
  • 自定义子集类型:如果需要支持属性值为原类型的子类型(比如string子类'admin' | 'user'),可以用:
matches<T extends keyof this>(params: { [K in T]: this[K] | SubType<this[K]> }): boolean {
  // 匹配逻辑
}

但如果只是严格匹配原属性的子集,Pick<this, T>依然是最优选择。

父类通用化实现(无需手动校验子类属性)

把matches移到父类后,利用keyof this的动态推导特性,父类不需要知道子类的具体属性,完全通用:

class Base {
  matches<T extends keyof this>(params: Pick<this, T>): boolean {
    return Object.entries(params).every(([key, value]) => {
      return this[key as keyof typeof this] === value;
    });
  }
}

class User extends Base {
  id: number;
  name: string;
  email: string;

  constructor(id: number, name: string, email: string) {
    super();
    this.id = id;
    this.name = name;
    this.email = email;
  }
}

// 调用示例
const user = new User(1, "Alice", "alice@example.com");
console.log(user.matches({ id: 1, name: "Alice" })); // true
console.log(user.matches({ email: "bob@example.com" })); // false

这里keyof this在子类实例调用时会自动推导为子类的属性键集合,Pick<this, T>也会自动匹配子类的属性类型,不需要在父类中做任何手动校验。

额外优化:处理引用类型匹配

如果属性是对象、数组这类引用类型,直接用===会比较引用地址,这时可以改用深度对比:

// 自己实现简单的深度对比函数
function deepEqual(a: any, b: any): boolean {
  if (a === b) return true;
  if (typeof a !== 'object' || typeof b !== 'object' || a == null || b == null) return false;
  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  if (keysA.length !== keysB.length) return false;
  for (const key of keysA) {
    if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false;
  }
  return true;
}

class Base {
  matches<T extends keyof this>(params: Pick<this, T>): boolean {
    return Object.entries(params).every(([key, value]) => {
      return deepEqual(this[key as keyof typeof this], value);
    });
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 13:45:31