TypeScript中如何用[K in keyof X]提取类的方法键并过滤非方法属性
提取类方法键并生成方法名映射类型的解决方案
问题描述
需要生成一个仅包含类中方法名的类型映射,但现有代码会保留类的所有键(包括属性)。例如针对TestClass,期望ClassMethods<TestClass>仅包含testMethod和testMethodAsync,但当前实现会把test属性也纳入自动补全列表。
原实现代码:
type ClassMethods<TClass> = { [K in keyof TClass] : TClass[K] extends (...args: any[])=>any ? "func" : never; }
问题原因
原代码仅为非方法类型的键赋值never,但TypeScript不会自动移除类型为never的属性,因此自动补全仍会显示这些键。
解决方案
使用TypeScript的**键重映射(Key Remapping)**特性,在遍历类的键时直接过滤掉非方法类型的键:
type ClassMethods<TClass> = { [K in keyof TClass as TClass[K] extends (...args: any[]) => any ? K : never]: "func"; };
代码说明
as关键字用于重映射键:判断当前键K对应的类型是否为函数(包括同步、异步、生成器函数),如果是则保留键K,否则替换为never。- TypeScript会自动移除值类型为
never的键,最终生成的类型仅包含类的方法名。
测试验证
class TestClass { constructor(public test: string) { this.test = test; } public testMethod() { return this.test; } public async testMethodAsync() { return this.test; } } const testClassMethods = null as ClassMethods<TestClass>; // 此时VS Code自动补全仅显示 testMethod 和 testMethodAsync
延伸:生成RPC客户端类型(同步方法转Async)
基于上述方法,可进一步实现将类中同步方法转为异步,同时保留原有异步/异步生成器方法的RPC客户端类型:
// 判断是否为同步函数(排除Promise返回和AsyncGenerator类型的函数) type IsSyncFunction<T> = T extends (...args: any[]) => Promise<any> ? never : T extends (...args: any[]) => AsyncGenerator<any, any, any> ? never : T extends (...args: any[]) => any ? true : false; // 生成RPC客户端类型 type RpcClient<T> = { [K in keyof T as T[K] extends (...args: any[]) => any ? K : never]: IsSyncFunction<T[K]> extends true ? (...args: Parameters<T[K]>) => Promise<ReturnType<T[K]>> : T[K]; }; // 使用示例 type TestRpcClient = RpcClient<TestClass>; // TestRpcClient 类型结构: // { // testMethod: () => Promise<string>; // 同步方法转为异步 // testMethodAsync: () => Promise<string>; // 原有异步方法保持不变 // }
内容的提问来源于stack exchange,提问作者Tomáš Zato
相关产品推荐
相关产品推荐

