Angular 弃用清单
已弃用的 API 和特性
Angular 力图兼顾创新与稳定。但有时,API 和特性已经过时,需要进行删除或替换,以便 Angular 可以及时跟上新的最佳实践、依赖项变更或者 Web 平台自身的变化。
为了使这些转换尽可能容易,我们在删除这些 API 和特性之前会弃用它们一段时间。这让你有时间将应用程序更新为最新的 API 和最佳实践。
本指南包含了当前已弃用的所有 Angular API 和特性的汇总表。
索引
为帮助你的项目面向未来,下表列出了所有已弃用的 API 和特性,并按它们将被移除的候选版本进行组织。每个项目都链接到本指南后面描述弃用原因和替换选项的部分。
特性区 |
API 或特性 |
将移除于 |
---|---|---|
@angular/common
|
|
v11 |
@angular/common
|
CurrencyPipe - DEFAULT_CURRENCY_CODE |
v11 |
@angular/common/http
|
XhrFactory |
v15 |
@angular/common/http/testing
|
|
v16 |
@angular/core
|
DefaultIterableDiffer |
v11 |
@angular/core
|
ReflectiveKey |
v11 |
@angular/core
|
RenderComponentType |
v11 |
@angular/core
|
|
v15 |
@angular/core
|
PlatformRef.bootstrapModuleFactory |
v15 |
@angular/core
|
getModuleFactory |
v16 |
@angular/core
|
ModuleWithComponentFactories |
v16 |
@angular/core
|
Compiler |
v16 |
@angular/core
|
CompilerFactory |
v16 |
@angular/core
|
NgModuleFactory |
v16 |
@angular/platform-browser-dynamic
|
|
v16 |
@angular/forms
|
和响应式表单一起使用 |
v11 |
@angular/upgrade
|
|
v11 |
@angular/upgrade
|
|
v11 |
@angular/upgrade
|
|
v11 |
@angular/upgrade
|
|
v15 |
模板语法 |
|
v11 |
腻子脚本 |
reflect-metadata |
v11 |
@angular/compiler-cli
|
|
v15 |
@angular/compiler-cli
|
fullTemplateTypeCheck |
v15 |
@angular/core
|
defineInjectable |
v11 |
@angular/core
|
entryComponents |
v11 |
@angular/core
|
ANALYZE_FOR_ENTRY_COMPONENTS |
v11 |
@angular/core
|
|
v15 |
@angular/core/testing
|
TestBed.get |
v12 |
@angular/core/testing
|
async |
v12 |
@angular/core/testing
|
|
v14 |
@angular/core/testing
|
|
v14 |
@angular/forms
|
|
v14 |
@angular/platform-server
|
renderModuleFactory |
v15 |
@angular/service-worker
|
SwUpdate#activated |
v16 |
@angular/service-worker
|
SwUpdate#available |
v16 |
模板语法 |
|
未指定 |
模板语法 |
|
v15 |
要了解 Angular CDK 和 Angular Material 的弃用情况,参阅变更记录。
已弃用的 API
本节包含所有当前已弃用的 API 的完整列表,其中包含一些可帮助你规划如何迁移到其替代品的详细信息。
@angular/common
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
CurrencyPipe - DEFAULT_CURRENCY_CODE |
{provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'}
|
v9 |
从 v11 开始,默认代码将从 |
@angular/common/http
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
XhrFactory |
|
v12 |
|
@angular/core
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
DefaultIterableDiffer |
n/a | v4 |
不再是公共 API。 |
ReflectiveInjector |
Injector.create()
|
v5 |
参见下文的 |
ReflectiveKey |
无 |
v5 |
无 |
defineInjectable |
ɵɵdefineInjectable
|
v8 |
仅在生成的代码中使用。任何源代码都不应依赖此 API。 |
entryComponents |
无 |
v9 |
参见下文的 |
ANALYZE_FOR_ENTRY_COMPONENTS |
无 |
v9 |
参见下文的 |
async |
waitForAsync |
v11 |
来自 |
getModuleFactory |
getNgModuleById |
v13 |
Ivy 允许直接使用 NgModule 类,而无需检索相应的工厂。 |
ViewChildren.emitDistinctChangesOnly / ContentChildren.emitDistinctChangesOnly
|
无(是问题 #40091的一部分) |
这是作为问题 #40091的错误修复的一部分引入的临时标志,将被删除。 |
|
|
|
v13 |
有了 ivy,不需要解析 Component factory,直接提供 Component Type 即可。 |
PlatformRef.bootstrapModuleFactory
|
PlatformRef.bootstrapModule |
v13 |
有了 ivy,就不需要解析 NgModule factory,直接提供 NgModule Type 即可。 |
ModuleWithComponentFactories
|
无 |
v13 |
Ivy JIT 模式不需要访问这个符号。 |
Compiler |
无 |
v13 |
Ivy JIT 模式不需要访问这个符号。 |
CompilerFactory |
无 |
v13 |
Ivy JIT 模式不需要访问这个符号。 |
NgModuleFactory |
使用基于非工厂的框架 API,如 |
v13 |
Ivy JIT 模式不需要访问这个符号。 |
|
|
v13 |
Angular 不再需要组件工厂来动态创建组件。使用 |
@angular/core/testing
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
TestBed.get |
TestBed.inject |
v9 |
行为没变,但类型安全。 |
async |
waitForAsync |
v10 |
行为相同,只是改名以免混淆。 |
|
无需更换 |
v13 |
Ivy 中不使用摘要文件。 |
|
无需更换 |
v13 |
Ivy 中未使用摘要文件。 |
@angular/platform-browser-dynamic
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
|
无 |
v13 |
不再需要此符号。 |
@angular/platform-server
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
renderModuleFactory |
renderModule |
v13 |
不再需要此符号。 |
@angular/forms
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
|
FormControlDirective |
v6 |
无 |
|
|
v11 |
无 |
@angular/service-worker
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
SwUpdate#activated |
|
v13 |
|
SwUpdate#available |
SwUpdate#versionUpdates |
v13 |
|
@angular/upgrade
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
所有入口点 |
@angular/upgrade/static |
v5 |
@angular/upgrade/static
API |
替代品 |
声明弃用于 |
备注 |
---|---|---|---|
getAngularLib |
getAngularJSGlobal |
v5 | |
setAngularLib |
setAngularJSGlobal |
v5 | |
|
|
v13 |
|
已弃用的特性
本部分列出了所有当前已弃用的特性,其中包括模板语法、配置选项以及上述已弃用 API部分中未列出的任何其他弃用特性。它还包括已弃用的 API 使用场景或 API 组合,以作为上述信息的补充。
Bazel 构建器和原理图
Angular Labs 中引入了 Bazel 构建器和原理图,让用户无需管理 Bazel 版本和 BUILD 文件即可试用 Bazel。此特性已被弃用。
Web 跟踪框架集成
Angular 以前支持与Web 跟踪框架 (WTF)集成,以对 Angular 应用程序进行性能测试。此集成未经维护,现已失效。因此,该集成在 Angular 版本 8 中被弃用,并且由于没有任何现有使用的证据,因此在版本 9 中被删除。
/deep/ 、 >>> 和 ::ng-deep 组件样式选择器
这类 shadow-dom-piercing 后代组合器已弃用,并且正在从主要浏览器和工具中删除支持。因此,在 v4 中,我们弃用了 Angular 对 /deep/
、 >>>
和 ::ng-deep
三个的支持。在正式移除之前, ::ng-deep
是首选,因为它与工具具有更广泛的兼容性。
bind- 、 on- 、 bindon- 和 ref- 前缀
模板前缀 bind-
、 on-
、 bindon-
和 ref-
在 v13 中已被弃用。模板应该使用更广为人知的语法进行绑定和引用:
-
[input]="value"
代替 bind-input="value"
-
[@trigger]="value"
代替 bind-animate-trigger="value"
-
(click)="onClick()"
代替 on-click="onClick()"
-
[(ngModel)]="value"
代替 bindon-ngModel="value"
-
#templateRef
代替 ref-templateRef
<template> 标签
<template>
标签在 v4 中已被弃用,以避免与 DOM 的同名元素发生冲突(例如在使用 Web 组件时)。使用 <ng-template>
代替。
和响应式表单一起使用 ngModel
在 Angular v6 中已不推荐把 ngModel
输入属性、ngModelChange
事件与响应式表单指令一起使用,并将在 Angular 的未来版本中删除。
现在已经弃用:
<input [formControl]="control" [(ngModel)]="value">
this.value = 'some value';
出于多种原因,此支持已被弃用。首先,开发人员发现这种模式令人困惑。似乎正在使用实际的 ngModel
指令,但实际上它是响应式表单指令上名为 ngModel
的输入/输出属性,它模拟了该指令的一些行为,但又不完全一样。它允许获取和设置值并拦截值事件,但 ngModel
的一些其他特性,例如使用 ngModelOptions
延迟更新或导出指令,不起作用。
另外,该模式混用了模板驱动和响应式这两种表单策略,这会妨碍我们获取任何一种策略的全部优点。 在模板中设置值的方式,也违反了响应式表单所遵循的“模板无关”原则;反之,在类中添加 FormControl
/FormGroup
层也破坏了“在模板中定义表单”的约定。
要在移除支持之前更新你的代码。你需要决定是坚持使用响应式表单指令(并使用响应式表单模式来获取/设置值)还是切换到模板驱动表单指令。
之后(选择 1 - 使用响应式表单):
<input [formControl]="control">
this.control.setValue('some value');
之后(选择 2 - 使用模板驱动表单):
<input [(ngModel)]="value">
this.value = 'some value';
默认情况下,当你使用此模式时,你将在开发模式下看到一次弃用警告。你可以通过在导入时配置 ReactiveFormsModule
来选择消除此警告:
imports: [
ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'})
],
或者,你可以选择为该模式的每个实例显示一个单独的警告,配置值为 "always"
。这可能有助于在更新代码时跟踪代码中使用模式的位置。
ReflectiveInjector
在 v5 中,Angular 用 StaticInjector
代替了 ReflectiveInjector
。该注入器不再需要 Reflect 的腻子脚本,对大部分开发人员来说都显著减小了应用的体积。
之前:
ReflectiveInjector.resolveAndCreate(providers);
之后:
Injector.create({providers});
loadChildren 字符串语法
当 Angular 第一次引入惰性路由时,还没有浏览器能支持动态加载额外的 JavaScript。因此 Angular 创建了自己的方案,所用的语法是 loadChildren: './lazy/lazy.module#LazyModule'
并且还构建了一些工具来支持它。现在,很多浏览器都已支持 ECMAScript 的动态导入,Angular 也正朝着这个新语法前进。
在版本 8 中,不推荐使用 loadChildren
路由规范的字符串语法,而是改用基于 import()
的新语法。
之前:
const routes: Routes = [{
path: 'lazy',
// The following string syntax for loadChildren is deprecated
loadChildren: './lazy/lazy.module#LazyModule',
}];
之后:
const routes: Routes = [{
path: 'lazy',
// The new import() syntax
loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
}];
版本 8 更新:当你更新到版本 8 时, ng update
命令会自动执行转换。在版本 7 之前, import()
语法仅适用于 JIT 模式(使用视图引擎)。
声明语法:遵循路由声明语法
loadChildren: () => import('...').then(m => m.ModuleName)
很重要,这样 ngc
才能发现惰性加载的模块和关联的 NgModule
。你可以在此处找到允许的语法结构的完整列表。这些限制将随着 Ivy 的发布而放宽,因为它将不再使用 NgFactories
。
JIT 模式下对反射元数据 polyfill 的依赖
Angular 应用程序,特别是依赖于 JIT 编译器的应用程序,过去常常需要 reflect-metadata API 的腻子脚本。
在 Angular 8.0 版(见#14473 )中移除了对这个腻子脚本的需求,这将使得大多数 Angular 应用程序不再需要此腻子脚本。因为此腻子脚本可能被第三方库依赖,因此不能从所有 Angular 项目中删除它,我们从 8.0 版本开始弃用对这个腻子脚本的要求。这样可以给库作者和应用程序开发人员足够的时间来评估他们是否需要此腻子脚本,并执行任何必要的重构以消除对它的依赖。
在典型的 Angular 项目中,这个腻子脚本不用于生产版本,因此删除它不会影响生产环境的应用程序。删除它是为了从整体上上简化构建设置并减少外部依赖项的数量。
@ViewChild() / @ContentChild() 默认使用静态解析
在版本 9 中,@ViewChild
和 @ContentChild
这两个查询的默认设置会改变,以修复查询中的 BUG 和意外行为。
为了应对这个变化,我们从版本 8 开始就要开始迁移所有应用和库,显式指定 @ViewChild
和 @ContentChild
查询的解析策略。
具体来说,这次迁移会添加一个显式的 “static” 标志,用来指出应该何时对该查询的结果进行赋值。等升级到版本 9 的时候,这个标志可以确保这些代码的工作方式都是一样的。
之前:
// query results sometimes available in `ngOnInit`, sometimes in `ngAfterViewInit` (based on template)
@ViewChild('foo') foo: ElementRef;
之后:
// query results available in ngOnInit
@ViewChild('foo', {static: true}) foo: ElementRef;
OR
// query results available in ngAfterViewInit
@ViewChild('foo', {static: false}) foo: ElementRef;
从版本 9 开始,static
标志将默认为 false
。那时候,可以安全地删除所有 {static: false}
标志,而且我们还会提供一个能帮你更新代码的原理图(schematic)。
注意:这个标志只适用于 @ViewChild
和 @ContentChild
这两个查询,这是因为 @ViewChildren
和 @ContentChildren
查询都没有静态和动态的概念(它们总是“动态”解析)。
@ContentChild() / @Input() 一起使用
以下模式已弃用:
@Input() @ContentChild(TemplateRef) tpldeprecated !: TemplateRef<any>;
不要再使用此模式,而应该将这两个装饰器分离到它们各自的属性中并添加回退逻辑,如下例所示:
@Input() tpl !: TemplateRef<any>;
@ContentChild(TemplateRef) inlineTemplate !: TemplateRef<any>;
无法赋值给模板变量
在以下示例中,双向绑定意味着应在 valueChange
事件触发时写入 optionName
。
<option *ngFor="let optionName of options" [(value)]="optionName"></option>
然而,在实践中,Angular 忽略了对模板变量的双向绑定。从版本 8 开始,不推荐对模板变量赋值。在未来的版本中,我们将抛出错误以指出不支持写入。
<option *ngFor="let optionName of options" [value]="optionName"></option>
在 platform-server 中绑定到 innerText
在服务器端渲染中使用的 Domino 不支持 innerText
,因此在平台服务器中的 “domino 适配器”中,如果尝试绑定到 innerText
,则有一些特殊代码可以退回到 textContent
。
这两个属性有细微的差别,因此在幕后切换到 textContent
可能会让用户感到惊讶。出于这个原因,我们弃用了这种行为。展望未来,用户应该在使用 Domino 时显式绑定到 textContent
。
wtfStartTimeRange 和所有 wtf* API
所有 wtf*
API 均已弃用,并将在未来版本中删除。
不再需要 entryComponents 和 ANALYZE_FOR_ENTRY_COMPONENTS
以前, NgModule
定义中的 entryComponents
数组用于告诉编译器将动态创建和插入哪些组件。使用 Ivy 后,这不再是必需的,并且可以从现有模块声明中删除 entryComponents
数组。这同样适用于 ANALYZE_FOR_ENTRY_COMPONENTS
注入令牌。
注意:如果构建将由 View Engine 应用程序使用的库,你可能仍需要保留它们。
不带泛型的 ModuleWithProviders 类型
一些 Angular 库,例如 @angular/router
和 @ngrx/store
,实现的 API 返回名为 ModuleWithProviders 的类型(通常使用名为 ModuleWithProviders
forRoot()
的方法)。这种类型代表一个 NgModule
以及其他提供者。 Angular 版本 9 已弃用没有明确泛型类型的 NgModule
ModuleWithProviders
类型。在 Angular 的未来版本中,泛型将不再是可选的。
如果你使用的是 CLI,则 ng update
应该会自动迁移代码。如果没有使用 CLI,则可以将任何缺失的泛型类型手动添加到应用程序中。例如:
之前
@NgModule({
/* ... */
})
export class MyModule {
static forRoot(config: SomeConfig): ModuleWithProviders {
return {
ngModule: SomeModule,
providers: [
{provide: SomeConfig, useValue: config}
]
};
}
}
之后:
@NgModule({
/* ... */
})
export class MyModule {
static forRoot(config: SomeConfig): ModuleWithProviders<SomeModule> {
return {
ngModule: SomeModule,
providers: [
{provide: SomeConfig, useValue: config}
]
};
}
}
输入 setter 强制类型转换
由于在 Angular 中引入了 strictTemplates
标志,编译器已经能够根据相应指令的声明输入类型对输入绑定进行类型检查。当 “getter/setter 对”用于输入时,可能需要让 setter 接受比 getter 返回的类型更宽泛的类型集,例如当 setter 首次转换输入值时。然而,在 TypeScript 4.3 之前,需要 getter/setter 对具有相同的类型,因此无法准确地声明此模式。
为了减轻这种限制,可以在对输入绑定进行类型检查时用到的指令中声明输入 setter 强制类型转换字段。但是,从 TypeScript 4.3 开始,此限制已被移除; setter 现在可以接受比 getter 返回的类型更宽泛的类型。这意味着不再需要输入强制类型转换字段,因为它们的效果可以通过拓宽 setter 的类型来实现。
例如,以下指令:
@Component({
})
export class SubmitButtonComponent {
static ngAcceptInputType_disabled: boolean|'';
private disabledValue = false;
@Input()
get disabled(): boolean {
return this.disabledValue;
}
set disabled(value: boolean) {
this.disabledValue = (value === '') || value;
}
}
可以重构如下:
@Component({
})
export class SubmitButtonComponent {
private disabledValue = false;
@Input()
get disabled(): boolean {
return this.disabledValue;
}
set disabled(value: boolean|'') {
this.disabledValue = (value === '') || value;
}
}
fullTemplateTypeCheck
使用 AOT 编译器编译你的应用程序时,你的模板会根据特定的严格级别进行类型检查。在 Angular 9 之前,fullTemplateTypeCheck
编译器选项只支持两个严格级别的模板类型检查。在版本 9 中引入了 strictTemplates
系列编译器选项,作为一种更细粒度的方法来配置模板的类型检查的严格程度。
fullTemplateTypeCheck
标志已被弃用,取代它的是新的 strictTemplates
选项及其相关的编译器选项。当前已配置为 fullTemplateTypeCheck: true
的项目可以迁移到以下编译器选项集以实现相同级别的类型检查:
{
"angularCompilerOptions": {
...
"strictTemplates": true,
"strictInputTypes": false,
"strictNullInputTypes": false,
"strictAttributeTypes": false,
"strictOutputEventTypes": false,
"strictDomEventTypes": false,
"strictDomLocalRefTypes": false,
"strictSafeNavigationTypes": false,
"strictContextGenerics": false,
...
}
}
由于 ViewEngine 弃用而导致的 JIT API 更改
在 ViewEngine 中, JIT 编译需要在应用程序中注入特殊的提供者(如 Compiler
、CompilerFactory
等)并调用相应的方法。使用 Ivy,如果 Component、NgModule 等尚未进行 AOT 编译 ,则 JIT 编译会隐式进行。这些特殊的提供者在 Ivy 中仍然可用,以便与 ViewEngine 向后兼容,从而使向 Ivy 的过渡更加顺畅。由于 ViewEngine 已被弃用并将很快被删除,因此这些符号现在也已被弃用。
重要说明:此弃用不会影响 Ivy 中的 JIT 模式(JIT 在 Ivy 中仍然可用,但是我们正在探索将来弃用它的可能性。请参阅 RFC:Angular JIT 编译模式的用例探索)。
TestRequest 接受 ErrorEvent 参数
Angular 提供了一些用于测试 HttpClient
的实用工具。 @angular/common/http/testing
中的 TestRequest
类会模拟 HTTP 请求对象以与 HttpTestingController
一起使用。
TestRequest
提供了一个 API 来模拟带有错误的 HTTP 响应。在早期版本的 Angular 中,此 API 接受 ErrorEvent
类型的对象,这与浏览器本机返回的错误事件类型不匹配。如果你要将 ErrorEvent
与 TestRequest
一起使用,就应该切换到 ProgressEvent
。
这是使用 ProgressEvent
的示例:
const mockError = new ProgressEvent('error');
const mockRequest = httpTestingController.expectOne(..);
mockRequest.error(mockError);
弃用的 CLI API 和选项
本节包含所有当前已弃用的 CLI 标志的完整列表。
@angular/cli
API/选项 |
可能移除于 |
备注 |
---|---|---|
--prod
|
v14 |
改用 |
ng update --all
|
v14 |
已无效果。 |
@angular-devkit/build-angular
API/选项 |
可能移除于 |
备注 |
---|---|---|
deployUrl
|
v15 |
使用 |
showCircularDependencies
|
v14 |
在项目代码中检测循环依赖的推荐方法是使用 lint 规则或其他外部工具。 |
Protractor 构建器 |
v14 |
作为 Protractor 弃用的一部分而弃用。 |
@angular-devkit/build-optimizer
整个 NPM 包已弃用。它一直是实验性的(从未达到 1.0.0
)并且一直是 Angular CLI 的内部包。所有相关特性都已移至 @angular-devkit/build-angular
。
删除的 API
从 11.0.0*开始,已经移除了以下 API:
包 |
API |
替代品 |
---|---|---|
@angular/router
|
preserveQueryParams
|
queryParamsHandling |
[style] 和 [style.prop] 绑定的样式清理
Angular 会清理 [style]
和 [style.prop]
绑定,以防止恶意代码通过 CSS url()
条目中的 javascript:
表达式进行插入。但是,大多数现代浏览器都已不再支持这些表达式的使用,所以这种清理只对 IE 6 和 7 才有意义。鉴于 Angular 不支持 IE 6 或 7,并且这种清理有性能代价,因此我们将不再清理 Angular 版本 10 中的样式绑定。
@angular/router 中的 loadChildren 字符串语法
不能再用 loadChildren
字符串语法来配置惰性路由。字符串语法已替换为动态导入语句。 DeprecatedLoadChildren
类型已从 @angular/router
中删除。
支持类 NgModuleFactoryLoader
、 SystemJsNgModuleLoader
和 SystemJsNgModuleLoaderConfig
类已从 @angular/core
中删除,并且 SpyNgModuleFactoryLoader
已从 @angular/router
中删除。
WrappedValue
WrappedValue
是为了供变更检测用的,它允许将相同的对象实例视为不同的。在 Observable
产生相同值实例的情况下,它通常与 async
管道一起使用。
鉴于此用例相对较少且特殊处理会影响应用程序性能, WrappedValue
API 已在 Angular 13 中删除。
如果你依赖同一个对象实例应该引起更改检测的行为,你有两个选择:
- 克隆结果值,使其具有新的标识。
- 显式调用
ChangeDetectorRef.detectChanges()
已强制更新。
更多建议: