属性“ ...”没有初始化程序,并且在构造函数中未明确分配


132

在我的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);
  }
}

但是在“ makes”属性中,我有一个错误。我不知道该怎么办...

错误

Answers:


73

我认为您正在使用最新版本的TypeScript。请参阅中的“严格类初始化”部分link

有两种方法可以解决此问题:

答:如果使用的是VSCode,则需要更改编辑器使用的TS版本。

B.在构造函数中声明数组时,只需对其进行初始化,

makes: any[] = [];

constructor(private makeService: MakeService) { 
   // Initialization inside the constructor
   this.makes = [];
}

抱歉,我是打字稿新手。你能说我的错在哪里吗?
Michael Kostiuchenko

2
如错误所示,您需要将变量初始化为某个值,从而使得:any [] = [];
Sajeetharan

1
您必须使用'Definite Assignment Assertion'来告诉打字稿该变量在运行时具有如下值:makes!: any[];
Hussein Akar

207

只需转到tsconfig.json并设置

"strictPropertyInitialization": false

摆脱编译错误。

否则,您需要初始化所有变量,这有点烦人


3
只要确保在“ strict”之后添加即可:否则,编译器似乎会再次打开它(尽管VS似乎知道它已关闭)。
星期一

52
这样,您将为所有项目禁用严格检查属性初始化。最好!在变量名称中添加后缀运算符,以忽略这种情况,或者在构造函数中初始化变量。
Matteo Guarnerio '18年

10
您建议您忽略编译器正在讲述的潜在问题,这确实不安全。如此投票。
奥尔加(Olga)

6
StrictPropertyInitialzer是在打字稿2.7中引入的标志。是否要启用所有这些标志并严格遵循所有规则或关闭某些验证,由每个人选择。每次都遵循所有规则完全没有道理。如果您的代码过于冗长和不利,并且大于优势,则应明确将其关闭。我并不是说这是所有情况下的最佳做法,但在大多数情况下是
绝对

2
当我将其设置为false时,仍然会出现相同的错误,这可能是什么问题?我使用VS码
sertsedat

66

这是因为TypeScript 2.7包括严格的类检查,所有属性都应在构造函数中初始化。一种解决方法是将!后缀添加为变量名称:

makes!: any[];

12
“!” 对于不能保证立即定义该值的常见情况,存在语法。这是一个逃生途径,因此不应该依赖它,因为它会使您的代码不安全。通常首选默认值。不过,很
高兴

@kingdaro是正确的。尽管通常可以使用它,但也可能导致代码无法正常使用。例如,在VS2017生成的基本Web应用程序中,通过添加“!”来更改fetchdata.components.ts中的预测分配。(公共预报!:WeatherForecast [];),这将导致它完全出错
IronRod

这是最好的解决方案,因为它紧接在@Input()装饰器之后(以新的角度),在读取任何给定组件时,它会自然读取并排除所有开发人员错误。
ELI7VH

22

Property has no initializer and is not definitely assigned in the constructortsconfig.json文件中添加一些配置以便在严格模式下编译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尝试输入绑定后才调用该方法,并且仅当有实际输入提供给绑定时才调用该方法。


这是使用“严格”模式时的正确答案
RnDrx

8

如果您确实不想初始化它,也可以执行以下操作。

makes?: any[];

8

您或者需要禁用--strictPropertyInitializationSajeetharan提到的,或者做这样的事情以满足初始化要求:

makes: any[] = [];

6

从TypeScript 2.7.2开始,如果在声明时未分配属性,则需要在构造函数中初始化属性。

如果您来自Vue,可以尝试以下操作:

  • 添加"strictPropertyInitialization": true到您的tsconfig.json

  • 如果您对禁用它不满意,也可以尝试一下makes: any[] | undefined。为此,您需要使用null check(?.)运算符访问属性,即this.makes?.length

  • 您也可以尝试makes!: any[];,这告诉TS该值将在运行时分配。

4

当您使用typescript@2.9.2进行升级时,其编译器严格遵循在组件类构造函数中声明数组类型的规则。

为了解决此问题,请更改代码在代码中声明的位置,或者避免编译器在“ tsconfig.json”文件中添加属性“ strictPropertyInitialization”:false并再次运行npm start。

Angular Web和移动应用程序开发可以访问www.jtechweb.in


3

您不能只使用确定分配声明吗?(请参阅https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#definite-assignment-assertions

即声明属性为makes!: any[];!确保打字稿在运行时肯定会有一个值。

抱歉,我还没有尝试过这个问题,但是当我在React中遇到完全相同的问题时,它对我来说非常有用。


因为它在官方文档中,所以我可以使用所有版本。谢谢!!
侯赛因·阿卡

3

在我的Angular项目中添加Node时遇到此错误-

TSError :?无法编译TypeScript:(path)/base.api.ts:19:13-错误TS2564:属性“ apiRoot Path”没有初始化程序,并且在构造函数中未明确分配。

私有apiRootPath:字符串;

解决方案-

添加"strictPropertyInitialization": false在“compilerOptions” tsconfig.json

的package.json -

"dependencies": {
    ...
    "@angular/common": "~10.1.3",
    "@types/express": "^4.17.9",
    "express": "^4.17.1",
    ...
}

引用URL- https://www.ryadel.com/zh-cn/ts2564-ts-property-has-no-initializer-typescript-error-fix-visual-studio-2017-vs2017/


2

该错误是合法的,可能会阻止您的应用崩溃。您键入makes为数组,但也可以未定义。

您有2个选项(而不是禁用打字稿存在的原因...):

1.在您的情况下,最好是键入makes可能未定义的类型。

makes?: any[]
// or
makes: any[] | undefined

在这种情况下,只要您尝试访问makes它,编译器就会通知您它可能是未定义的。例如,如果您// <-- Not okgetMakes完成之前写以下行或getMakes失败,则会引发编译错误。否则您的应用程序将崩溃。

makes[0] // <-- Not ok
makes.map(...) // <-- Not ok

if (makes) makes[0] // <-- Ok
makes?.[0] // <-- Ok
(makes ?? []).map(...) // <-- Ok

2.您可以通过编写以下代码来假设它永远不会失败,并且您绝不会尝试在初始化之前访问它(风险!)。因此,编译器不会理会它。

makes!: any[]

0

改变

fieldname?: any[]; 

对此:

fieldname?: any; 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.