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

TypeScript属性装饰器编译报TS1240错误如何解决?

问题描述

我正在开发一个TypeScript项目,使用属性装饰器对类属性进行验证。项目已开启Experimental decorators(实验性装饰器),以下是简化后的代码:

interface ValidatorConfig {
  [property: string]: {
    [validatableProp: string]: string[]; // ['required', 'positive']
  };
}

const registeredValidators: ValidatorConfig = {};

function Required(target: any, propName: string) { 
  registeredValidators[target.constructor.name] = {
    [propName]: ['required']
  };
}

function PositiveNumber(target: any, propName: string) {
  registeredValidators[target.constructor.name] = {
    [propName]: ['positive']
  };
}

function validate(obj: any): boolean {
  const objValidatorConfig = registeredValidators[obj.constructor.name];
  if (!objValidatorConfig) {
    return true;
  }

  let isValid = true;

  for (const prop in objValidatorConfig) {
    for (const validator of objValidatorConfig[prop]) {
      switch (validator) {
        case 'required':
          isValid = isValid && !!obj[prop];
          break;
        case 'positive':
          isValid = isValid && obj[prop] > 0;
          break;
      }
    }
  }
  return isValid;
}

class Course {
  @Required
  title: string;

  @PositiveNumber
  price: number;

  constructor(t: string, p: number) {
    this.title = t;
    this.price = p;
  }
}

const createCourse = new Course("Hello Book", 1000);

if (!validate(createCourse)) {
  alert('Invalid input, try again');
}

使用tsc app.ts编译代码时,出现以下错误:

app.ts:57:4 - error TS1240: Unable to resolve signature of property decorator when called as an expression.
Argument of type 'ClassFieldDecoratorContext<Course, string> & { name: "title"; private: false; static: false; }' is not assignable to parameter of type 'string'.

57   @Required
~~~~~~~~

app.ts:59:4 - error TS1240: Unable to resolve signature of property decorator when called as an expression.
Argument of type 'ClassFieldDecoratorContext<Course, number> & { name: "price"; private: false; static: false; }' is not assignable to parameter of type 'string'.

59   @PositiveNumber
~~~~~~~~~~~~~~

请问如何解决属性装饰器引发的TS1240错误?


解决方案

TS1240错误的核心原因是你使用了旧版属性装饰器签名,但当前TypeScript的实验性装饰器已采用新的ClassFieldDecorator规范,参数结构发生了变化。同时你的代码还存在隐藏问题:多个装饰器会覆盖验证配置,导致只有最后一个装饰器生效。以下是修复步骤:

1. 调整装饰器函数的签名

新的类字段装饰器接收两个核心参数:

  • target: 类的原型(实例字段)或类本身(静态字段)
  • context: ClassFieldDecoratorContext对象,包含字段名称、是否静态等元信息

修改Required和PositiveNumber装饰器:

function Required(target: any, context: ClassFieldDecoratorContext) {
  // 获取类名称
  const className = target.constructor.name;
  // 将字段名称转为字符串类型
  const propName = String(context.name);
  
  // 初始化类的验证配置,避免覆盖已有配置
  if (!registeredValidators[className]) {
    registeredValidators[className] = {};
  }
  // 初始化字段的验证规则,避免覆盖已有规则
  if (!registeredValidators[className][propName]) {
    registeredValidators[className][propName] = [];
  }
  
  registeredValidators[className][propName].push('required');
}

function PositiveNumber(target: any, context: ClassFieldDecoratorContext) {
  const className = target.constructor.name;
  const propName = String(context.name);
  
  if (!registeredValidators[className]) {
    registeredValidators[className] = {};
  }
  if (!registeredValidators[className][propName]) {
    registeredValidators[className][propName] = [];
  }
  
  registeredValidators[className][propName].push('positive');
}

2. 修复验证配置覆盖问题

原代码直接通过赋值registeredValidators[target.constructor.name] = {...}覆盖配置,导致同一类的多个字段、同一字段的多个装饰器无法共存。现在改为先检查并初始化配置对象,再追加验证规则,确保所有装饰器的规则都能被正确记录。

3. 验证修复效果

修改后重新编译代码,TS1240错误会消失。同时可以测试多装饰器场景(比如给price同时添加@Required和@PositiveNumber),验证逻辑会正确执行所有规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:12:40