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

TypeScript API服务:如何统一校验方法调用时的存在性?

嘿,这个需求完全可行,而且确实能帮你省去大量重复的校验代码!我之前做TypeScript API服务时也遇到过类似场景,用Proxy代理就能完美解决这个问题——不需要在每个方法里写重复逻辑,只需要在基类的构造函数里做一次统一拦截就行。

核心思路

利用ES6的Proxy来拦截类实例的方法访问,当调用get开头的方法时,自动触发统一的校验逻辑,校验通过后再执行原方法。这样所有子类的get类方法都能共享这套校验逻辑,不用重复编写。

具体实现步骤

1. 编写基础API基类

先定义一个BaseApi基类,在它的构造函数里返回一个Proxy实例,负责拦截所有属性访问:

class BaseApi<T extends object> {
  constructor(target: T) {
    return new Proxy(target, {
      // 拦截属性获取(包括方法)
      get(targetInstance, methodName: string) {
        // 只针对get开头的方法做统一处理
        if (methodName.startsWith('get')) {
          const originalMethod = (targetInstance as any)[methodName];
          
          // 返回一个包装后的函数,先执行校验再调用原方法
          return function(...args: any[]) {
            // 校验1:检查该方法是否存在
            if (typeof originalMethod !== 'function') {
              throw new Error(`API方法 ${methodName} 不存在,请检查方法名是否正确`);
            }
            
            // 这里可以添加更多统一校验逻辑,比如参数合法性检查
            if (args.length === 0) {
              throw new Error(`调用 ${methodName} 时需要传入至少一个参数`);
            }
            
            // 校验通过,执行原方法并返回结果
            return originalMethod.apply(targetInstance, args);
          };
        }
        
        // 非get开头的方法/属性,直接返回原内容
        return (targetInstance as any)[methodName];
      }
    }) as T;
  }
}

2. 子类继承基类实现业务方法

你的具体API服务类只需要继承BaseApi,专注实现业务逻辑即可,不用管校验:

class UserApi extends BaseApi<UserApi> {
  constructor() {
    // 把当前实例传给基类的Proxy
    super(this);
  }

  // 业务方法:获取用户信息
  getUser(userId: number) {
    return { id: userId, name: '张三', email: 'zhangsan@example.com' };
  }

  // 业务方法:获取用户权限
  getUserPermissions(userId: number) {
    return ['view', 'edit'];
  }

  // 非get开头的方法,不会触发统一校验
  updateUser(userId: number, userData: { name: string }) {
    return { success: true, message: '用户信息更新成功' };
  }
}

3. 测试效果

现在调用API方法时,会自动触发统一校验:

const userApi = new UserApi();

// 正常调用:校验通过,返回结果
console.log(userApi.getUser(123)); 
// 输出:{ id: 123, name: '张三', email: 'zhangsan@example.com' }

// 调用不存在的get方法:触发校验报错
userApi.getNonExistentMethod(); 
// 抛出错误:API方法 getNonExistentMethod 不存在,请检查方法名是否正确

// 调用get方法但不传参数:触发参数校验报错
userApi.getUser(); 
// 抛出错误:调用 getUser 时需要传入至少一个参数

补充:TypeScript类型支持

上面的基类用了泛型<T extends object>,确保子类的方法类型能被TypeScript正确识别,不会因为Proxy而丢失类型提示——你在IDE里调用userApi.getUser()时,依然能看到参数和返回值的类型提示。

为什么不用其他方案?

  • 装饰器:虽然也能实现,但需要给每个get方法手动加装饰器,还是有重复操作,不符合你“避免重复”的需求。
  • 手动在构造函数绑定:逐个监听方法调用的话,代码繁琐且扩展性差,新增get方法时还要手动更新绑定逻辑。

而Proxy的方案是一次性统一拦截,后续新增get方法时完全不需要修改基类代码,自动享受统一校验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:22:51