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

如何在装饰器中获取参数名?实现方法参数校验装饰器求助

实现参数校验装饰器来精简你的代码

完全理解你的需求——用装饰器把重复的参数校验逻辑抽离出来,让业务代码更清爽对吧?咱们可以先搞一个通用的枚举参数校验装饰器,这样不仅能复用在orderBy和sort上,以后其他需要枚举校验的参数也能直接用。

第一步:创建通用的枚举校验装饰器

不管是orderBy还是sort,本质都是校验参数是否在指定的合法值列表里,所以咱们写一个装饰器工厂函数,接受参数名和合法值数组,返回对应的装饰器:

// TypeScript版本,带类型注解更严谨
function ValidateEnum(paramName: string, allowedValues: string[]) {
  return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function(...args: any[]) {
      // 匹配方法参数的索引(对应getUsers的参数顺序:offset, limit, orderBy, sort)
      const paramIndex = ['offset', 'limit', 'orderBy', 'sort'].indexOf(paramName);
      if (paramIndex === -1) {
        throw new Error(`参数 ${paramName} 不存在于方法参数列表中`);
      }

      const paramValue = args[paramIndex];
      // 校验参数合法性
      if (!allowedValues.includes(paramValue)) {
        // 这里返回你需要的HTTP响应,比如适配Express的格式
        return {
          status: 400,
          message: `参数 ${paramName} 不合法,允许的值为:${allowedValues.join(', ')}`
        };
      }

      // 校验通过,执行原方法逻辑
      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
}

如果是纯JavaScript环境,去掉类型注解即可:

function ValidateEnum(paramName, allowedValues) {
  return function(target, propertyKey, descriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function(...args) {
      const paramIndex = ['offset', 'limit', 'orderBy', 'sort'].indexOf(paramName);
      if (paramIndex === -1) {
        throw new Error(`参数 ${paramName} 不存在于方法参数列表中`);
      }

      const paramValue = args[paramIndex];
      if (!allowedValues.includes(paramValue)) {
        return {
          status: 400,
          message: `参数 ${paramName} 不合法,允许的值为:${allowedValues.join(', ')}`
        };
      }

      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
}

第二步:在getUsers方法上使用装饰器

现在你只需要给getUsers方法加上两个装饰器注解,就能完成参数校验,业务代码里完全不用再写校验逻辑:

class UserController {
  // 可以把合法值存在类属性里,方便统一维护
  private orderByFields = ['createdAt', 'updatedAt'];
  private sortValues = ['ASC', 'DESC'];

  @ValidateEnum('orderBy', ['createdAt', 'updatedAt'])
  @ValidateEnum('sort', ['ASC', 'DESC'])
  getUsers(offset: number, limit: number, orderBy: string, sort: string) {
    // 这里只需要写核心业务逻辑就行!
    console.log('参数校验通过,执行用户查询逻辑');
    // ... 你的原有业务代码
  }
}

额外优化:动态读取合法值列表

如果你不想在装饰器里硬编码合法值,还可以改成从类实例的属性中动态获取,这样以后修改合法值只需要更新类属性,不用动装饰器:

function ValidateEnumFromInstance(paramName: string, allowedValuesKey: string) {
  return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function(...args: any[]) {
      const paramIndex = ['offset', 'limit', 'orderBy', 'sort'].indexOf(paramName);
      if (paramIndex === -1) {
        throw new Error(`参数 ${paramName} 不存在于方法参数列表中`);
      }

      const paramValue = args[paramIndex];
      // 从实例属性中读取合法值列表
      const allowedValues = this[allowedValuesKey];
      if (!allowedValues.includes(paramValue)) {
        return {
          status: 400,
          message: `参数 ${paramName} 不合法,允许的值为:${allowedValues.join(', ')}`
        };
      }

      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
}

使用时改成这样:

class UserController {
  private orderByFields = ['createdAt', 'updatedAt'];
  private sortValues = ['ASC', 'DESC'];

  @ValidateEnumFromInstance('orderBy', 'orderByFields')
  @ValidateEnumFromInstance('sort', 'sortValues')
  getUsers(offset: number, limit: number, orderBy: string, sort: string) {
    // ... 业务代码
  }
}

对比前后代码

原来你需要在方法里写:

if (!includes(this.orderByFields, orderBy)) { return HTTP响应 }
if (!includes(this.sortValues, sort)) { return HTTP响应 }

现在只需要两行装饰器注解,业务代码彻底摆脱了校验逻辑,是不是清爽太多了?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:39:51