修改 Angular Component 构造函数参数被认为是
修改构造函数参数被认为是 breaking change:
Making any changes to the class constructor signature. Note that super calls need to be updated in classes extending ours.
如果我们在构造函数里引入新的参数,这被认为是 breaking change:
对于升级到新次要版本以及之前通过使用较少参数调用 super() 构造函数在其代码库中扩展我们的服务的任何客户,这将导致 breaking change(特别是编译错误),例如在以下示例中 :
export class CustomService extends SpartacusService {
constructor(promotionService: PromotionService){
super(promotionService); // <--------- wrong constructor signature
/* customer's constructor logic here */
}
}
正确做法:
// TODO(#10946): make CartItemContextSource a required dependency
constructor(
promotionService: PromotionService,
// eslint-disable-next-line @typescript-eslint/unified-signatures
cartItemContextSource: CartItemContextSource
);
/**
* @deprecated since 3.1
*/
constructor(promotionService: PromotionService);
constructor(
protected promotionService: PromotionService,
@Optional() protected cartItemContextSource?: CartItemContextSource
) {}
/* ... */
method() {
console.log(this.cartItemContextSource?.item$);
}
注意以下三点:
(1) 添加 ?使新的构造函数参数可选。否则,传递较少参数的客户将收到编译错误。
(2) 在类的逻辑中,允许新的构造函数参数为空或未定义。您可以通过使用可选链 (?.) 访问新依赖项的任何属性来实现此目的,例如 this.cartItemContextSource?.item$。如果不这样做,扩展我们的类并向 super() 构造函数传递较少参数的客户将在我们的逻辑中收到运行时错误,因为 this.cartItemContextSource 对象将是未定义的。
(3) 如果您的类可能未提供新的构造函数依赖项(例如,依赖项服务不是providedIn:'root',或者在DOM中有条件地提供),则在构造函数依赖项之前使用@Optional()。否则,当没有条件提供依赖时,客户将收到无法解析依赖的 Angular 运行时错误。在构造函数依赖项之前使用 @Optional() 告诉 Angular 在无法注入值时优雅地回退到 null。
除了上述要求,我们还鼓励您执行以下操作:
(1) 添加内联注释,例如 // TODO(#ticket-number): make X a required dependency,以引用下一个主要版本的计划工作。
(2) 在实现上方添加构造函数的两个替代声明。 最上面的声明必须是最新的。
这是因为,在使用 SSR 的生产构建中,只有第一个声明用于解决依赖关系。 将 @deprecated 自 X.Y 添加到您的 JSDoc 评论也很有帮助。 包含此内容后,客户的 IDE 可以警告他们正在使用的旧构造函数签名(参数较少)已被弃用,这可以促使他们尽早迁移到新签名。
Using the Inject Decorator for Dependencie
将 @Inject 用于依赖项时,不应包含任何构造函数声明。 相反,您应该只包含构造函数定义。
当您构建库时(例如,当您运行 ng build --prod core 时),ng-packagr 工具仅使用第一个构造函数声明来解析注入的依赖项,而忽略构造定义。 但是,构造函数声明中不支持 Inject 装饰器,因此它不能用于解析那里的依赖关系。 如果你包含一个带有依赖的构造函数声明,ng-packagr 工具将无法解析依赖,你会得到一个错误,如下所示:
ERROR: Internal error: unknown identifier []
一个错误的例子:
import { PLATFORM_ID } from '@angular/core';
/*...*/
// Do not add any constructor declarations when using @Inject to resolve a dependency
constructor(
platformId: any, // this dependency will not be resolved, nor can it be fixed with @Inject, because the Inject decorator is not supported here!
newService?: NewService
) {}
constructor(
protected platformId: any,
) {}
constructor(
@Inject(PLATFORM_ID) protected platformId: any,
protected newService?: NewService
) {}
一个正确的例子:
import { PLATFORM_ID } from '@angular/core';
/*...*/
constructor(
@Inject(PLATFORM_ID) protected platformId: any,
protected newService?: NewService
) {}