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
相关产品推荐
相关产品推荐

