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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:20:16