属性'...'没有初始化程序,并且在构造函数中没有明确赋值

Mic*_*nko 45 javascript typescript angular

在我的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);
  }
}
Run Code Online (Sandbox Code Playgroud)

但在"制造"属性中我有一个错误.我不知道该怎么做...

错误

Ste*_*ane 81

Property has no initializer and is not definitely assigned in the constructor当我们在文件中添加一些配置tsconfig.json以便以严格模式编译 Angular 项目时,我们可能会收到以下消息:

"compilerOptions": {
  "strict": true,
  "noImplicitAny": true,
  "noImplicitThis": true,
  "alwaysStrict": true,
  "strictNullChecks": true,
  "strictFunctionTypes": true,
  "strictPropertyInitialization": true,
Run Code Online (Sandbox Code Playgroud)

事实上,编译器会抱怨成员变量在使用之前没有定义。

对于编译时未定义的成员变量的示例,具有@Input指令的成员变量:

@Input() userId: string;
Run Code Online (Sandbox Code Playgroud)

我们可以通过声明变量是可选的来使编译器保持沉默:

@Input() userId?: string;
Run Code Online (Sandbox Code Playgroud)

但是,我们将不得不处理变量未定义的情况,并用一些这样的语句使源代码变得混乱:

if (this.userId) {
} else {
}
Run Code Online (Sandbox Code Playgroud)

相反,知道这个成员变量的值会及时定义,也就是说,它会在使用之前定义,我们可以告诉编译器不要担心它没有被定义。

告诉编译器这一点的方法是添加! definite assignment assertion运算符,如下所示:

@Input() userId!: string;
Run Code Online (Sandbox Code Playgroud)

现在,编译器知道这个变量虽然没有在编译时定义,但应该在运行时定义,并且在使用它之前及时定义。

现在由应用程序确保该变量在使用之前已定义。

作为附加保护,我们可以在使用变量之前断言该变量已被定义。

我们可以断言变量已定义,即所需的输入绑定实际上是由调用上下文提供的:

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();
}
Run Code Online (Sandbox Code Playgroud)

知道变量已定义,现在可以使用该变量:

ngOnChanges() {
  this.userService.get(this.userId)
    .subscribe(user => {
      this.update(user.confirmedEmail);
    });
}
Run Code Online (Sandbox Code Playgroud)

请注意,ngOnInit即使没有向绑定提供实际输入,该方法也会在输入绑定尝试之后调用。

而该ngOnChanges方法在输入绑定尝试之后调用,并且仅当向绑定提供了实际输入时才调用。

  • 这是使用“严格”模式时的正确答案 (4认同)
  • 这应该被认为是正确的答案,因为它解决了问题,而不是仅仅转动部分 linting。 (4认同)

Mar*_*uka 73

只需转到tsconfig.json并设置即可

"strictPropertyInitialization": false
Run Code Online (Sandbox Code Playgroud)

摆脱编译错误.

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

  • 这样,您将禁用所有项目的严格检查属性初始化.最好将`!`postfix运算符添加到变量名中,只是忽略这种情况,或者在构造函数中初始化变量. (9认同)
  • StrictPropertyInitialzer是在打字稿2.7中引入的标志。是否要启用所有这些标志并严格遵循所有规则或关闭某些验证,由每个人选择。每次都遵循所有规则完全没有道理。如果您的代码过于冗长和不利,并且大于优势,则应明确将其关闭。我并不是说这在所有情况下都是最佳做法,但在大多数情况下是绝对可行的选择... (4认同)
  • 正如我在回答中提到的,您有两种选择,要么禁用验证,要么初始化所有变量。每个人都可以选择哪个项目能让您从项目中受益更多。 (4认同)
  • 只要确保你在"严格"之后添加:true,否则转换器似乎再打开它(虽然VS似乎知道它已关闭). (2认同)
  • 您建议忽略编译器正在讲述的潜在问题,这确实不安全。如此投票。 (2认同)
  • 当我将其设置为 false 时,它​​仍然给我同样的错误,可能是什么问题?我正在使用 VS 代码 (2认同)
  • 谢谢!在 `tsconfig.json` .. `compilerOptions` ...我将 strict 的值从 true 更新为 false ... `"strict": false` 并解决了问题。 (2认同)
  • 对于其他想知道的人,必须将此条目添加到 tsconfig.json 的“compilerOptions”部分中 (2认同)

xgq*_*rms 47

有很多解决方案

\n
\n

演示代码

\n
\n
class Plant {\n  name: string;\n  // \xe2\x9d\x8c Property \'name\' has no initializer and is not definitely assigned in the constructor.ts(2564)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

解决方案

\n
    \n
  1. 添加“未定义”类型
  2. \n
\n
class Plant {\n  name: string | undefined;\n}\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 添加明确的赋值断言
  2. \n
\n
class Plant {\n  name!: string;\n}\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 用初始值声明
  2. \n
\n
class Plant {\n  name: string = \'\';\n}\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 使用带有初始值的构造函数
  2. \n
\n
class Plant {\n  name: string;\n  constructor() {\n    this.name = \'\';\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 通过参数使用构造函数和初始化值
  2. \n
\n
class Plant {\n  name: string;\n  constructor(name: string) {\n    this.name = name ?? \'\';\n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 的简写5
  2. \n
\n
class Plant {\n  constructor(public name: string = name ?? \'\') {\n    // \n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

tsconfig.json

\n
\n

不建议

\n
\n
{\n  "compilerOptions": {\n+   "strictPropertyInitialization": false,\n-   "strictPropertyInitialization": true,\n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

参考文献

\n

https://www.typescriptlang.org/docs/handbook/2/classes.html#--strictpropertyinitialization

\n


小智 36

  1. 转到tsconfig.json

  2. “compilerOptions”中添加“strictPropertyInitialization”:false :

在此输入图像描述


cri*_*ari 35

转到您的tsconfig.json文件并进行更改, "noImplicitReturns": false 然后在属性下添加"strictPropertyInitialization": false到您的tsconfig.json文件中"compilerOptions"这是我的tsconfig.json文件的样子

tsconfig.json

{
  ...
  "compilerOptions": {
        ....
        "noImplicitReturns": false,
        ....
        "strictPropertyInitialization": false
  },
  "angularCompilerOptions": {
     ......
  }  
}
Run Code Online (Sandbox Code Playgroud)

希望这会有所帮助! 祝你好运

  • IMO,这有点倒退。 (4认同)

Saj*_*ran 27

我认为您使用的是最新版本的TypeScript.请参阅中的"严格类初始化"部分link.

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

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

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

makes: any[] = [];

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

  • 您必须使用“明确赋值断言”来告诉打字稿该变量在运行时将具有一个值,如下所示:“makes!:any[];” (135认同)
  • 在构造函数中初始化变量是 Angular 的反模式。不要这样做。 (5认同)
  • 因为错误说你需要将变量初始化为某个值使得:any [] = []; (2认同)

Har*_*ath 24

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

makes!: any[];
Run Code Online (Sandbox Code Playgroud)

  • "!" 对于那些不能保证立即定义值的常见情况,存在语法.它是一个逃生舱,不应该依赖它,因为它可以使你的代码不那么安全.通常首选默认值.很高兴知道它存在 (5认同)
  • 这是最好的解决方案,因为它直接位于 @Input() 装饰器之后(在新的角度中),当读取任何给定组件时,它会自然读取并剔除任何开发错误。 (4认同)

Ale*_*nic 24

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

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

1.在您的情况下,最好输入makes为可能未定义。

makes?: any[]
// or
makes: any[] | undefined
Run Code Online (Sandbox Code Playgroud)

因此,每当您尝试访问makes它可能未定义时,编译器都会通知您。否则,如果以下// <-- Not ok行在getMakes完成之前执行或getMakes失败,您的应用程序将崩溃并抛出运行时错误。那绝对不是你想要的。

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

if (makes) makes[0] // <-- Ok
makes?.[0] // <-- Ok
(makes ?? []).map(...) // <-- Ok
Run Code Online (Sandbox Code Playgroud)

2.你可以假设它永远不会失败,并且你永远不会在初始化之前尝试通过编写下面的代码来访问它(有风险!)。所以编译器不会关心它。

makes!: any[] 
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是唯一正确的解决方案。我对其他答案感到震惊。 (4认同)

Sum*_*mit 22

2021 年更新:

有像“strictPropertyInitialization”这样的属性

只需转到 tsconfig.json 并设置

“严格”:假

摆脱编译错误。

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

此错误背后的原因是:

  • 与 javascript 相比,typescript 是一种更安全的语言。
  • 尽管通过启用严格功能增强了这种安全性。所以每次初始化变量时,打字稿都希望它们分配一个值。

  • 可怕的建议,抛弃类型安全,这样你会看到更少的错误,而不是为了安全而放弃一些便利。 (8认同)

小智 14

在make变量后加一个问号(?)。

  makes?: any[];
  vehicle = {};

  constructor(private makeService: MakeService) { }
Run Code Online (Sandbox Code Playgroud)

现在应该可以了。我正在使用 Angular 12,它适用于我的代码。


小智 14

更好的方法是将感叹号添加到变量的末尾,您确定它不会是未定义的或空的,例如您正在使用需要从模板加载的 ElementRef ,并且不能在构造函数中定义,执行如下操作

class Component {
 ViewChild('idname') variable! : ElementRef;
}
Run Code Online (Sandbox Code Playgroud)


sam*_*vic 14

如果您不想更改tsconfig.json,您可以这样定义您的类:

class Address{
  street: string = ''
}
Run Code Online (Sandbox Code Playgroud)

或者,您也可以像这样继续:

class Address{
  street!: string
}
Run Code Online (Sandbox Code Playgroud)

添加感叹号“!” 在变量名称之后,Typescript 将确保该变量不为 null 或未定义。


Spe*_*pin 13

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

makes?: any[];
Run Code Online (Sandbox Code Playgroud)


Joh*_*edy 11

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

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

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

  • 如果您对禁用它不满意,您也可以试试这个makes: any[] | undefined。这样做需要您使用空检查(?.)运算符访问属性,即this.makes?.length

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


M K*_*aei 10

tsconfig.json文件中的“compilerOptions”内添加:

"strictPropertyInitialization": false,
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Geo*_*ris 8

如果要基于接口初始化对象,可以使用以下语句将其初始化为空。

myObj: IMyObject = {} as IMyObject;
Run Code Online (Sandbox Code Playgroud)


小智 8

这是因为 Typescript 2.7.2 包含严格的类检查,所有属性都应在构造函数中声明。因此,要解决这个问题,只需添加一个感叹号 (!),例如:

name!:string;
Run Code Online (Sandbox Code Playgroud)


Pin*_*aki 7

在我的 Angular 项目中添加 Node 时出现此错误 -

TS错误:?无法编译 TypeScript: (path)/base.api.ts:19:13 - 错误 TS2564:属性 'apiRoot Path' 没有初始值设定项,并且未在构造函数中明确分配。

私有 apiRootPath:字符串;

解决方案 -

添加"strictPropertyInitialization": falsetsconfig.json 的'compilerOptions' 中。

我的package.json -

"dependencies": {
    ...
    "@angular/common": "~10.1.3",
    "@types/express": "^4.17.9",
    "express": "^4.17.1",
    ...
}
Run Code Online (Sandbox Code Playgroud)

参考网址 - https://www.ryadel.com/en/ts2564-ts-property-has-no-initializer-typescript-error-fix-visual-studio-2017-vs2017/


小智 7

新版本的打字稿引入了严格的类初始化,这意味着您需要在构造函数主体中初始化类中的所有属性,或者通过属性初始值设定项。在打字稿文档中检查它 以避免这种情况,您可以添加(!或?)属性

make!: any[] or make? : any[] 
Run Code Online (Sandbox Code Playgroud)

否则,如果您希望在项目中永久删除严格的类检查,您可以在 tsconfig.json 文件中设置 strictPropertyInitialization": false

"compilerOptions": { .... "noImplicitReturns": false, .... "strictPropertyInitialization": false },

  • '!' 和有什么不一样?和 '?' ? (2认同)
  • @pouyada '!' 是断言赋值声明,表示无论分配什么,即使打字稿无法拾取它。`?` 是可选的,意味着它可能存在也可能不存在,但您的组件应该为这两种情况做好准备。 (2认同)

Ale*_*xei 6

另一种修复变量必须保持未初始化(并且在运行时处理)的情况的方法是添加undefined到类型(这实际上是 VC 代码建议的)。例子:

@Input() availableData: HierarchyItem[] | undefined;
@Input() checkableSettings: CheckableSettings | undefined;
Run Code Online (Sandbox Code Playgroud)

根据实际使用情况,这可能会导致其他问题,因此我认为最好的方法是尽可能初始化属性。


max*_*sam 6

这已在 Angular Github 中进行了讨论,网址为https://github.com/angular/angular/issues/24571

我认为Angular 的推荐给出了很好的建议:

对于角度分量,请使用以下规则来决定:
a) 添加初始值设定项
b) 使字段可选?
c) 保留!

  • 如果字段注释为@input- 使字段可选 b) 或添加初始值设定项 a)。
  • 如果组件用户需要输入 - 在ngOnInitc) 中添加断言并应用。
  • 如果该字段已注释@ViewChild@ContentChild - 将该字段设为可选 b)。
  • 如果该字段用@ViewChildrenor注释@ContentChildren- 添加回 '!' - C)。
  • 具有初始值设定项的字段,但它位于ngOnInit. - 将初始值设定项移至构造函数 a)。
  • 具有初始值设定项的字段,但它存在ngOnInit且无法移动,因为它依赖于其他@input字段 - 添加回 '!' - C)。


小智 6

1)您可以像下面的代码一样应用它。当你这样做时,系统不会给出错误。

“明确赋值断言” (!)告诉 TypeScript 我们知道这个值

详细信息

@Injectable()
export class Contact {
  public name !:string;
  public address!: Address;
  public digital!: Digital[];
  public phone!: Phone[];
}
Run Code Online (Sandbox Code Playgroud)

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

3)第三种选择是创建一个 get 属性并分配一个值,如下所示

  export class Contact {
      public name :string="";
      public address: Address=this._address;
    
      get _address(): Address {
        return new Address();
      }
     
    }
Run Code Online (Sandbox Code Playgroud)


小智 6

就我而言,它根据新的打字稿严格功能使用不同的声明:

@ViewChild(MatSort, {static: true}) sort!: MatSort;
Run Code Online (Sandbox Code Playgroud)

如果在 tsonfig.json 中禁用 typescript 新的严格功能

"compilerOptions": {
  ///
  ,
  "strictPropertyInitialization":false
}
Run Code Online (Sandbox Code Playgroud)

旧的 Angular 的引导代码运行良好

@ViewChild(MatSort) sort: MatSort;
Run Code Online (Sandbox Code Playgroud)

感谢 Arunkumar Gudelli (2022),这里有 4 种解决问题的方法https://www.angularjswiki.com/angular/property-has-no-initializer-and-is-not-definitely-assigned-in-the-constructor /


ksh*_*ine 5

您需要禁用--strictPropertyInitializationSajeetharan引用的,或者执行以下操作以满足初始化要求:

makes: any[] = [];
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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

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


And*_*ndy 5

你不能只使用一个明确的赋值断言吗?(见https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#define-assignment-assertions

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

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