Свойство «…» не имеет инициализатора и точно не назначается в конструкторе.


104

в моем приложении 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);
  }
}

но в свойстве "делает" у меня ошибка. Я не знаю, что с этим делать ...

ошибка

Ответы:


59

Думаю, вы используете последнюю версию TypeScript. См. Раздел «Строгая инициализация класса» в link.

Есть два способа исправить это:

A. Если вы используете VSCode, вам необходимо изменить версию TS, которую использует редактор.

Б. Просто инициализируйте массив, когда вы объявляете его внутри конструктора,

makes: any[] = [];

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

извините, я новичок в машинописи. Вы можете сказать, в чем моя ошибка?
— Михаил Костюченко 06

2
поскольку ошибка говорит, что вам нужно инициализировать переменную некоторым значением: any [] = [];
— Sajeetharan

158

Просто зайдите в tsconfig.json и установите

"strictPropertyInitialization": false

чтобы избавиться от ошибки компиляции.

В противном случае вам нужно инициализировать все ваши переменные, что немного раздражает


3
Просто убедитесь, что вы добавили это после "strict": true, иначе транспиллер, кажется, снова включит его (хотя VS, похоже, знает, что он выключен).
— monty

35
Таким образом вы отключите строгую проверку инициализации свойств для всего проекта. Лучше добавить !к имени переменной постфиксный оператор, чтобы просто игнорировать этот случай, или инициализировать переменную внутри конструктора.
— Маттео Гварнерио

6
Вы предлагаете игнорировать потенциальные проблемы, о которых сообщает компилятор, это небезопасно. Итак, голос против.
— Ольга

6
StrictPropertyInitialzer - это флаг, представленный в машинописном тексте 2.7. Каждый может выбрать, хотите ли вы включить все эти флаги и строго следовать всем правилам или отключить некоторую проверку. Совершенно бессмысленно каждый раз следовать всем правилам. Если ваш код становится слишком многословным, имеет недостатки и больше, чем преимущества, вам следует обязательно отключить его. Я не говорю, что это лучшая практика во всех случаях, но в большинстве случаев это определенно жизнеспособный вариант ...
— Мартин Чука

1
Как я уже упоминал в своем ответе, у вас есть два варианта: отключить проверку ИЛИ инициализировать все переменные. Каждый может выбрать, что принесет вам больше пользы от проекта к проекту.
— Мартин Чука

46

Это потому, что TypeScript 2.7 включает строгую проверку классов, в которой все свойства должны быть инициализированы в конструкторе. Обходной путь - добавить в !качестве постфикса к имени переменной:

makes!: any[];

11
Знак "!" синтаксис существует для тех распространенных случаев, когда вы не можете гарантировать, что значение будет определено немедленно. Это аварийный люк, и на него не следует полагаться, так как он может сделать ваш код менее безопасным. Обычно предпочтительнее значение по умолчанию. Тем не менее,
— приятно

@kingdaro прав. Хотя это обычно можно использовать, это также может привести к тому, что плоский код не будет работать. Например, в базовом веб-приложении, созданном VS2017, измените назначение прогнозов в fetchdata.components.ts, добавив знак '!' (общедоступные прогнозы !: WeatherForecast [];) и это приведет к полной ошибке
— IronRod

14

Мы можем получить сообщение 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,

Действительно, компилятор затем жалуется, что переменная-член не определена перед использованием.

В качестве примера переменной-члена, которая не определена во время компиляции, переменная-член, имеющая @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

Вам нужно либо отключить то, --strictPropertyInitializationчто упоминал Саджитаран, либо сделать что-то вроде этого, чтобы удовлетворить требование инициализации:

makes: any[] = [];

5

Вы также можете сделать следующее, если действительно не хотите инициализировать его.

makes?: any[];

4

Когда вы обновляете с помощью typescript@2.9.2, его компилятор строго соблюдает правила для объявления типа массива внутри конструктора класса компонента.

Чтобы исправить эту проблему, либо измените код, который объявлен в коде, либо избегайте добавления компилятором свойства "strictPropertyInitialization": false в файл "tsconfig.json" и снова запустите npm start.

Angular Разработка веб-приложений и мобильных приложений вы можете посетить на сайте www.jtechweb.in


4

Начиная с TypeScript 2.7.2, вы должны инициализировать свойство в конструкторе, если оно не было присвоено в момент объявления.

Если вы переходите с Vue, вы можете попробовать следующее:

  • Добавьте "strictPropertyInitialization": trueв свой tsconfig.json

  • Если вас не устраивает его отключение, вы также можете попробовать это makes: any[] | undefined. Для этого необходимо получить доступ к свойствам с помощью ?.оператора null check ( ), т.е.this.makes?.length

  • Вы также можете попробовать makes!: any[];, это говорит TS, что значение будет присвоено во время выполнения.

2

Разве вы не можете просто использовать утверждение с определенным назначением? (См. Https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#definite-assignment-assertions. )

т.е. объявление свойства как makes!: any[];The! гарантирует, что машинописный текст определенно будет иметь значение во время выполнения.

Извините, я не пробовал это в angular, но у меня это отлично сработало, когда у меня была точно такая же проблема в React.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.