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

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[];
SpeedOfSpin
источник
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, что значение будет присвоено во время выполнения.
codejockie
источник
2

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

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

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

Энди
источник