在我的 Angular 应用程序中,我有一个组件:
import { MakeService } from './../../services/make.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-vehicle-form',
templateUrl: './vehicle-form.component.html',
styleUrls: ['./vehicle-form.component.css']
})
export class VehicleFormComponent implements OnInit {
makes: any[];
vehicle = {};
constructor(private makeService: MakeService) { }
ngOnInit() {
this.makeService.getMakes().subscribe(makes => { this.makes = makes
console.log("MAKES", this.makes);
});
}
onMakeChange(){
console.log("VEHICLE", this.vehicle);
}
}
但在“制造”属性中我有一个错误。我不知道该怎么办...
https://i.stack.imgur.com/QpJLJ.png
只需转到 tsconfig.json 并设置
"strictPropertyInitialization": false
摆脱编译错误。
否则,您需要初始化所有变量,这有点烦人
我认为您使用的是最新版本的 TypeScript。请参阅 link
中的“严格类初始化”部分。
有两种方法可以解决此问题:
A. 如果您使用的是 VSCode,您需要更改编辑器使用的 TS 版本。
B. 声明时初始化数组
makes: any[] = [];
或在构造函数内部:
constructor(private makeService: MakeService) {
// Initialization inside the constructor
this.makes = [];
}
makes!: any[];
ctrl+shift+p
并在下拉列表中输入 typescript
,然后选择“选择 TypeScript 版本”
这是因为 TypeScript 2.7 包含一个严格的类检查,所有属性都应该在构造函数中初始化。一种解决方法是将 !
作为后缀添加到变量名称:
makes!: any[];
在 tsconfig.json
文件中添加一些配置时,我们可能会收到消息 Property has no initializer and is not definitely assigned in the constructor
,以便在严格模式下编译 Angular 项目:
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"alwaysStrict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
实际上,编译器随后会抱怨在使用之前未定义成员变量。
对于在编译时未定义的成员变量的示例,具有 @Input
指令的成员变量:
@Input() userId: string;
我们可以通过声明变量可能是可选的来使编译器静音:
@Input() userId?: string;
但是,我们将不得不处理未定义变量的情况,并用一些这样的语句使源代码混乱:
if (this.userId) {
} else {
}
相反,知道这个成员变量的值会及时定义,也就是说,它会在使用之前定义,我们可以告诉编译器不要担心它没有被定义。
告诉编译器的方法是添加 ! definite assignment assertion
运算符,如下所示:
@Input() userId!: string;
现在,编译器明白这个变量虽然没有在编译时定义,但应该在运行时定义,并且在使用它之前及时定义。
现在由应用程序确保在使用之前定义此变量。
作为一个额外的保护,我们可以在使用它之前断言正在定义的变量。
我们可以断言变量已定义,即所需的输入绑定实际上是由调用上下文提供的:
private assertInputsProvided(): void {
if (!this.userId) {
throw (new Error("The required input [userId] was not provided"));
}
}
public ngOnInit(): void {
// Ensure the input bindings are actually provided at run-time
this.assertInputsProvided();
}
知道变量已定义,现在可以使用该变量:
ngOnChanges() {
this.userService.get(this.userId)
.subscribe(user => {
this.update(user.confirmedEmail);
});
}
请注意,在输入绑定尝试之后调用 ngOnInit
方法,即使没有向绑定提供实际输入也是如此。
而 ngOnChanges
方法是在输入绑定尝试之后调用的,并且只有在绑定提供了实际输入时才调用。
转到您的 tsconfig.json
文件并更改属性:
"noImplicitReturns": false
然后添加
"strictPropertyInitialization": false
在 "compilerOptions"
属性下。
您的 tsconfig.json
文件应如下所示:
{
...
"compilerOptions": {
....
"noImplicitReturns": false,
....
"strictPropertyInitialization": false
},
"angularCompilerOptions": {
......
}
}
希望这会有所帮助!
祝你好运
该错误是合法,可能会阻止您的应用崩溃。您将 makes
键入为一个数组,但它也可以是未定义的。
您有 2 个选项(而不是禁用打字稿存在的原因......):
1. 在您的情况下,最好将 makes
键入为可能未定义。
makes?: any[]
// or
makes: any[] | undefined
因此,每当您尝试访问 makes
时,编译器都会通知您它可能未定义。否则,如果在 getMakes
完成之前执行了下面的 // <-- Not ok
行,或者如果 getMakes
失败,您的应用程序将崩溃并引发运行时错误。这绝对不是你想要的。
makes[0] // <-- Not ok
makes.map(...) // <-- Not ok
if (makes) makes[0] // <-- Ok
makes?.[0] // <-- Ok
(makes ?? []).map(...) // <-- Ok
2. 你可以假设它永远不会失败,并且在初始化之前你永远不会尝试通过编写下面的代码来访问它(有风险!)。所以编译器不会关心它。
makes!: any[]
进一步来说,
您的代码设计可能会更好。定义局部和可变变量不是一个好习惯。您应该管理服务内的数据存储:
首先是零安全的,
其次,能够分解大量代码(包括打字、加载状态和错误)
最后是为了避免过多和无用的reftech。
下面的例子试图展示这一点,但我没有测试它,它可以改进:
type Make = any // Type it
class MakeService {
private readonly source = new BehaviorSubject<Make[] | undefined>(undefined);
loading = false;
private readonly getMakes = (): Observable<Make[]> => {
/* ... your current implementation */
};
readonly getMakes2 = () => {
if (this.source.value) {
return this.source.asObservable();
}
return new Observable(_ => _.next()).pipe(
tap(_ => {
this.loading = true;
}),
mergeMap(this.getMakes),
mergeMap(data => {
this.source.next(data);
return data;
}),
tap(_ => {
this.loading = false;
}),
catchError((err: any) => {
this.loading = false;
return throwError(err);
}),
);
};
}
@Component({
selector: 'app-vehicle-form',
template: `
<div *ngIf="makeService.loading">Loading...</div>
<div *ngFor="let vehicule of vehicules | async">
{{vehicle.name}}
</div>
`,
styleUrls: ['./vehicle-form.component.css']
})
export class VehicleFormComponent implements OnInit {
constructor(public makeService: MakeService) {}
readonly makes = this.makeService.getMakes2().pipe(
tap(makes => console.log('MAKES', makes))
);
readonly vehicules = this.makes.pipe(
map(make => make/* some transformation */),
tap(vehicule => console.log('VEHICLE', vehicule)),
);
ngOnInit() {
this.makes.subscribe(makes => {
console.log('MAKES', makes);
});
}
}
:
之前添加 !
更为常见。
2021 年更新:
有像“strictPropertyInitialization”这样的属性
只需转到 tsconfig.json 并设置
“严格”:假
摆脱编译错误。
否则,您需要初始化所有变量,这有点烦人。
此错误背后的原因是:
与 javascript 相比,typescript 是一种更安全的语言。
尽管通过启用严格的功能来增强这种安全性。所以每次初始化变量时打字稿都希望它们分配一个值。
您要么需要禁用 Sajeetharan 提到的 --strictPropertyInitialization
,要么执行以下操作以满足初始化要求:
makes: any[] = [];
如果您真的不想初始化它,也可以执行以下操作。
makes?: any[];
如果要基于接口初始化对象,可以使用以下语句将其初始化为空。
myObj: IMyObject = {} as IMyObject;
在使变量之后放一个问号(?)。
makes?: any[];
vehicle = {};
constructor(private makeService: MakeService) { }
它现在应该可以工作了。我正在使用 angular 12,它适用于我的代码。
从 TypeScript 2.7.2 开始,如果在声明时未分配属性,则需要在构造函数中初始化该属性。
如果你来自 Vue,你可以尝试以下方法:
添加 "strictPropertyInitialization": true 到您的 tsconfig.json
如果你对禁用它不满意,你也可以试试这个 make: any[] |不明确的。这样做需要您使用空检查 (?.) 运算符访问属性,即 this.makes?.length
你也可以试试 make!:any[];,这告诉 TS 该值将在运行时分配。
有很多解决方案
演示代码
class Plant {
name: string;
// ❌ Property 'name' has no initializer and is not definitely assigned in the constructor.ts(2564)
}
解决方案
添加“未定义”类型
class Plant {
name: string | undefined;
}
添加明确的赋值断言
class Plant {
name!: string;
}
用初始值声明👍
class Plant {
name: string = '';
}
使用带有初始值的构造函数👍
class Plant {
name: string;
constructor() {
this.name = '';
}
}
通过参数使用构造函数和初始化值👍
class Plant {
name: string;
constructor(name: string) {
this.name = name ?? '';
}
}
5的简写👍
class Plant {
constructor(public name: string = name ?? '') {
//
}
}
tsconfig.json
不建议
{
"compilerOptions": {
+ "strictPropertyInitialization": false,
- "strictPropertyInitialization": true,
}
}
参考
https://www.typescriptlang.org/docs/handbook/2/classes.html#--strictpropertyinitialization
击球手的方法是将感叹号添加到您确定它不应为 undefined 或 null 的变量的末尾,例如,您使用的 ElementRef 需要从模板加载并且不能在构造函数中定义,执行如下操作
class Component {
ViewChild('idname') variable! : ElementRef;
}
如果你不想改变你的 tsconfig.json,你可以像这样定义你的类:
class Address{
street: string = ''
}
或者,您也可以这样进行:
class Address{
street!: string
}
通过添加感叹号“!”在您的变量名之后,Typescript 将确保该变量不为空或未定义。
在我的 Angular 项目中添加节点时出现此错误 -
TS错误:?无法编译 TypeScript:(路径)/base.api.ts:19:13 - 错误 TS2564:属性 'apiRoot Path' 没有初始化程序,并且未在构造函数中明确分配。私有 apiRootPath:字符串;
解决方案 -
在 tsconfig.json 的 'compilerOptions' 中添加了 "strictPropertyInitialization": false
。
我的 package.json -
"dependencies": {
...
"@angular/common": "~10.1.3",
"@types/express": "^4.17.9",
"express": "^4.17.1",
...
}
在 tsconfig.json 文件中,在“compilerOptions”中添加:
"strictPropertyInitialization": false,
https://i.stack.imgur.com/SUiVW.png
属性“...”没有初始化程序,并且在 Angular 的构造函数错误修复中未明确分配
解决方案 1:禁用 strictPropertyInitialization 标志
在 Angular 应用程序中修复此错误的简单方法是在 tsconfig.json 文件的 typescript 编译器选项中禁用 --strictPropertyInitialization 标志。
"compilerOptions": {
///
,
"strictPropertyInitialization":false
}
解决方案 2:向属性添加未定义类型
有一个未定义的属性是可以的。
因此,在声明变量时,将未定义的类型添加到属性中。
employees: Employee[];
//Change to
employees : Employee[] | undefined;
解决方案 3:向属性添加明确的赋值断言
如果您知道我们将在稍后的时间点分配该物业。
最好为属性添加明确的赋值断言。即员工。
employees!: Employee[];
解决方案 4:将初始化程序添加到属性
消除这种类型错误的另一种方法是向属性添加显式初始化程序。
employees: Employee[] = [];
解决方案 5:构造函数中的赋值
否则,我们可以为构造函数中的属性分配一些默认值。
employees: Employee[];
constructor() {
this.employees=[];
}
当你使用 typescript@2.9.2 升级时,它的编译器严格遵循组件类构造函数中数组类型声明的规则。
要解决此问题,请更改代码中声明的代码或避免编译器在“tsconfig.json”文件中添加属性“strictPropertyInitialization”:false 并再次运行 npm start 。
Angular web 和移动应用程序开发你可以去 www.jtechweb.in
在变量必须保持未初始化(并且在运行时处理)的情况下解决的另一种方法是将 undefined
添加到类型(这实际上是 VC Code 建议的)。例子:
@Input() availableData: HierarchyItem[] | undefined;
@Input() checkableSettings: CheckableSettings | undefined;
根据实际使用情况,这可能会导致其他问题,因此我认为最好的方法是尽可能初始化属性。
@Input() availableData: HierarchyItem[] | undefined;
与写 @Input() availableData?: HierarchyItem[]
相同;)
新版本的 typescript 引入了严格的类初始化,这意味着您需要在构造函数主体中初始化类中的所有属性,或者通过属性初始化程序。 check it in typescript doccumntation 为避免这种情况,您可以使用属性添加(!或?)
make!: any[] or make? : any[]
否则,如果您希望在项目中永久删除严格的类检查,您可以在 tsconfig.json 文件中设置 strictPropertyInitialization": false
"compilerOptions": { .... "noImplicitReturns": false, .... "strictPropertyInitialization": false },
!
是自信的分配声明,表示无论分配什么,即使打字稿无法拾取它。 ?
是可选的,表示它可能存在也可能不存在,但您的组件应为任何一种情况做好准备。
你不能只使用一个明确的赋值断言吗? (见https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#definite-assignment-assertions)
即,将属性声明为 makes!: any[];
!确保打字稿在运行时肯定会有一个值。
抱歉,我没有在 Angular 中尝试过这个,但是当我在 React 中遇到完全相同的问题时,它对我很有用。
1)您可以像下面的代码一样应用它。当你这样做时,系统不会给出错误。
“Definite Assignment Assertion”(!)告诉 TypeScript 我们知道这个值
@Injectable()
export class Contact {
public name !:string;
public address!: Address;
public digital!: Digital[];
public phone!: Phone[];
}
2)第二种方法是在这里创建一个构造函数并定义值。
export class Contact {
public name :string;
public address: Address;
public digital: Digital[];
public phone: Phone[];
constructor( _name :string,
_address: Address,
_digital: Digital[],
_phone: Phone[])
{
this.name=_name;
this.address=_address;
this.digital=_digital;
this.phone=_phone;
}
}
3) 第三种选择是创建一个 get 属性并分配一个值,如下所示
export class Contact {
public name :string="";
public address: Address=this._address;
get _address(): Address {
return new Address();
}
}
在 tsconfig.json 中添加这两行
"noImplicitReturns": true,
"strictPropertyInitialization": false,
并确保 strict 设置为 true
改变
fieldname?: any[];
对此:
fieldname?: any;
您可以像这样在构造函数中声明属性:
export class Test {
constructor(myText:string) {
this.myText= myText;
}
myText: string ;
}
这已在 Angular Github https://github.com/angular/angular/issues/24571 中讨论过
我想这就是每个人都会去的地方
引自https://github.com/angular/angular/issues/24571#issuecomment-404606595
For angular components, use the following rules in deciding between:
a) adding initializer
b) make the field optional
c) leave the '!'
If the field is annotated with @input - Make the field optional b) or add an initializer a).
If the input is required for the component user - add an assertion in ngOnInit and apply c.
If the field is annotated @ViewChild, @ContentChild - Make the field optional b).
If the field is annotated with @ViewChildren or @ContentChildren - Add back '!' - c).
Fields that have an initializer, but it lives in ngOnInit. - Move the initializer to the constructor.
Fields that have an initializer, but it lives in ngOnInit and cannot be moved because it depends on other @input fields - Add back '!' - c).
就我而言,它可以根据新的打字稿严格功能使用不同的声明:
@ViewChild(MatSort, {static: true}) sort!: MatSort;
如果在 tsonfig.json 中禁用打字稿新的严格功能
"compilerOptions": {
///
,
"strictPropertyInitialization":false
}
旧 Angular 的指南代码运行良好
@ViewChild(MatSort) sort: MatSort;
感谢 Arunkumar Gudelli (2022),这里有 4 种解决问题的方法https://www.angularjswiki.com/angular/property-has-no-initializer-and-is-not-definitely-assigned-in-the-constructor/
只需转到 tsconfig.ts 并将“strictPropertyInitialization”:false,添加到 compilerOptions 对象中。
如果还没有解决,请重新打开您的代码编辑器。
例子:
"compilerOptions" : {
"strictPropertyInitialization": false,
}
注释 tsconfig.json 文件中的 //"strict": true
行。
!
后缀运算符添加到变量名称中,以忽略这种情况,或者在构造函数中初始化变量。