Skip to content

Class 使用 Angular 特性但未装饰:修复 NG2007 错误

问题描述

在使用 Angular 开发过程中,当创建一个包含 @Input() 等 Angular 特性的基类,并由其他组件继承时,可能会遇到以下编译错误:

ERROR in src/app/base-screen.ts:4:14 - error NG2007:
Class is using Angular features but is not decorated. Please add an explicit Angular decorator.

这种情况通常发生在这样的场景中:

typescript
// 基类 BaseComponent
export class BaseComponent {
    @Input() TeamName: string;
    @Input() teamSize: number;
    @Input() players: any;
}

// 子组件 CricketComponent
@Component({
  selector: 'app-cricket',
  templateUrl: './cricket.component.html',
  styleUrls: ['./cricket.component.scss']
})
export class cricketComponent extends BaseComponent implements OnInit {
  // ...
}

解决方案

根据 Angular 版本的不同,有以下几种解决方案:

方案一:使用 @Directive 装饰器(推荐)

从 Angular 10 开始,可以使用 @Directive() 装饰器来标记基类:

typescript
import { Directive, Input } from '@angular/core';

@Directive()
export abstract class BaseComponent {
    @Input() TeamName: string;
    @Input() teamSize: number;
    @Input() players: any;
}

优势

  • 不需要提供模板信息
  • 不会强制要求依赖注入兼容性
  • 代码简洁且语义明确

方案二:使用 @Component 装饰器

在 Angular 9+ 中,也可以使用 @Component 装饰器:

typescript
import { Component } from '@angular/core';

@Component({
  template: ''
})
export abstract class BaseComponent {
    @Input() TeamName: string;
    @Input() teamSize: number;
    @Input() players: any;
}

注意事项

使用 @Component 装饰器时,基类的构造函数参数必须能被依赖注入系统解析。如果包含常量或字面量参数,可能需要配置额外的 DI 提供者。

方案三:使用 @Injectable 装饰器

另一种可行的方法是使用 @Injectable() 装饰器:

typescript
import { Injectable, Input } from '@angular/core';

@Injectable()
export abstract class BaseComponent {    
    @Input() TeamName: string;
    @Input() teamSize: number;
    @Input() players: any;
}

方案四:检查 TypeScript 版本

在某些情况下,特别是 Angular 15 中,TypeScript 版本不兼容可能导致此错误。可以尝试使用特定版本的 TypeScript:

bash
npm i typescript@4.8.2 -D --save-exact

方案五:检查代码结构

确保类的定义位置正确,不要在 @Component 声明和组件类之间定义其他类:

typescript
// 正确:在其他类之前定义
export class Y {
  // ...
}

@Component({
  selector: 'app-X',
  templateUrl: './X.component.html',
  styleUrls: ['./X.component.css']
})
export class XComponent implements OnInit {
  // 使用 Y 类
  todos : Y[] = [new Y(1), new Y(2), new Y(3)]
  
  constructor() { }

  ngOnInit(): void {
  }
}

最佳实践建议

  1. 使用抽象类:将基类声明为 abstract 可以防止直接实例化
  2. 选择适当的装饰器:根据具体情况选择 @Directive()@Component()@Injectable()
  3. 保持代码整洁:确保类定义的位置不会导致编译器混淆
  4. 版本兼容性:保持 Angular 和 TypeScript 版本的兼容性

总结

NG2007 错误是由于使用了 Angular 特性(如 @Input())的类缺少必要的装饰器导致的。根据 Angular 版本和具体需求,可以选择添加 @Directive()@Component()@Injectable() 装饰器来解决此问题。推荐使用 @Directive() 作为基类的装饰器,因为它既满足了 Angular 的要求,又不会引入不必要的复杂性。