TypeScript中如何定义类的键类型且对应值匹配指定接口?
TypeScript:筛选类中值类型匹配指定接口的键
需要定义一个类型,满足以下两个条件:
- 该类型是类的方法、变量、setter/getter的键;
- 该键对应的值(或setter的参数类型)属于指定接口。
示例场景
有两个接口FirstInterface、SecondInterface,以及类Class1包含变量、setter和getter。现在需要在抽象类Class2中定义一个抽象方法getCorrectKey,其返回值只能是Class1中对应值为FirstInterface的键(预期可选值:'setter1' | 'setter3'),同时保证setState方法无TypeScript错误。
基础代码:
interface FirstInterface { field1: string; field2: number; } interface SecondInterface { randomField: string; } class Class1 { variable: string; set setter1(value: FirstInterface): void {} get setter1(): FirstInterface { return { field1: '', field2: 0 }; } set setter2(value: SecondInterface): void {} set setter3(value: FirstInterface): void {} }
此前尝试的泛型写法(abstract getCorrectKey<T extends keyof Class1>(): Class1[T] extends FirstInterface ? T : never)会导致setState方法中currentState的类型为never,不符合预期。
解决方案
1. 定义工具类型
创建一个工具类型,筛选出类中getter返回类型为指定接口或setter参数类型为指定接口的键:
type KeysMatchingSetterOrGetter<T, U> = { [K in keyof T]: // 匹配getter返回类型为U的键 (T[K] extends U ? K : never) | // 匹配setter参数类型为U的键 (T extends { set [K](value: U): void } ? K : never) }[keyof T];
2. 修正抽象类Class2
在Class2中使用该工具类型定义getCorrectKey的返回值类型:
abstract class Class2 { constructor(protected class1Instance: Class1) {} // 返回类型固定为符合条件的键:'setter1' | 'setter3' abstract getCorrectKey(): KeysMatchingSetterOrGetter<Class1, FirstInterface>; private setState(state: FirstInterface): void { const key = this.getCorrectKey(); // 处理只有setter的键(如setter3)读取时为undefined的情况 const currentState = this.class1Instance[key]; this.class1Instance[key] = { ...(currentState || {}), ...state }; } }
3. 继承时的类型校验
继承Class2时,TypeScript会自动校验返回值是否符合要求:
class InheritingClass extends Class2 { override getCorrectKey(): KeysMatchingSetterOrGetter<Class1, FirstInterface> { // ❌ TypeScript会抛出错误:类型不匹配 // return 'random'; // return 'variable'; // ✅ 无错误 return 'setter1'; // return 'setter3'; } }
说明
- 工具类型
KeysMatchingSetterOrGetter通过遍历类的所有键,分别判断getter和setter的类型是否匹配指定接口,最终返回符合条件的键的联合类型。 - 对于只有setter的键(如
setter3),读取时类型为undefined,因此在setState中需要处理该情况(比如使用currentState || {})。
内容的提问来源于stack exchange,提问作者Roman Šimík
相关产品推荐
相关产品推荐

