Властивість '...' не має ініціалізатора і точно не призначена в конструкторі


133

у моєму додатку 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);
  }
}

але у властивості "робить" я маю помилку. Я не знаю, що з цим робити ...

помилка

Відповіді:


80

Я думаю, ви використовуєте останню версію TypeScript. Будь ласка, дивіться розділ "Строга ініціалізація класу" в link.

Є два способи виправити це:

А. Якщо ви використовуєте VSCode, вам потрібно змінити версію TS, яку використовує редактор.

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

makes: any[] = [];

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

вибачте, я новачок у машинописі. Чи можете ви сказати, де моя помилка?
Михайло Костюченко

2
як повідомляє помилка, потрібно ініціалізувати змінну деяким значенням: any [] = [];
Sajeetharan

1
Ви повинні використовувати 'Певне твердження про призначення', щоб повідомити машинопис, що ця змінна матиме значення під час виконання наступним чином:makes!: any[];
Хуссейн Акар

210

Просто перейдіть до tsconfig.json і встановіть

"strictPropertyInitialization": false

щоб позбутися помилки компіляції.

В іншому випадку вам потрібно ініціалізувати всі свої змінні, що трохи дратує


4
Просто переконайтеся, що ви додали, що після "суворо": true, інакше, здається, транспілятор вмикає його знову (хоча VS, здається, знає, що він вимкнений).
Монті

52
Таким чином ви вимкнете сувору перевірку ініціалізації властивостей для всього проекту. Краще додати !оператор postfix до імені змінної, щоб просто ігнорувати цей випадок або ініціалізувати змінну всередині конструктора.
Matteo Guarnerio

10
Ви пропонуєте ігнорувати потенційні проблеми, про які розповідає компілятор, це насправді не безпечно. Тож проти.
Ольга

7
StrictPropertyInitialzer - це прапор, введений у машинопис 2.7. Кожен вирішує, чи хочете ви активувати всі ці прапори, і суворо дотримуватись усіх правил, або вимкнути перевірку. Немає абсолютно сенсу щоразу дотримуватися всіх правил. Якщо ваш код стає занадто багатослівним і негативним, і він більший за переваги, вам слід його безумовно вимкнути. Я не кажу, що це найкраща практика у всіх випадках, але це безумовно життєздатний варіант у більшості випадків ...
Мартін Чука

2
Як я вже згадував у своїй відповіді, у вас є два варіанти, або вимкнути перевірку АБО ініціалізувати всі змінні. Кожен вирішує, який результат від проекту до проекту буде вам більше корисний.
Мартін Чука

67

Це тому, що TypeScript 2.7 включає сувору перевірку класу, де всі властивості повинні бути ініціалізовані в конструкторі. Обхідним шляхом є додавання !як постфікса до імені змінної:

makes!: any[];

12
"!" синтаксис існує для тих типових випадків, коли ви не можете гарантувати, що значення буде визначено негайно. Це евакуаційний люк, і на нього не слід покладатися, оскільки він може зробити ваш код менш безпечним. Зазвичай типовим є значення за замовчуванням. Хоча б добре знати, що він існує
kingdaro

@kingdaro має рацію. Хоча це зазвичай можна використовувати, це також може призвести до коду, який не працює. Як приклад, у базовій веб-програмі, створеній VS2017, змініть призначення для прогнозів у fetchdata.components.ts, додавши знак! (публічні прогнози !: WeatherForecast [];) і це призведе до його повного виходу з ладу
IronRod

Це найкраще рішення, оскільки воно безпосередньо після декоратора @Input () (у новому angular), читаючи будь-який заданий компонент, він читає природним чином і видаляє помилки розробника.
ELI7VH

23

Ми можемо отримати повідомлення 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

Ви також можете зробити наступне, якщо ви дійсно не хочете ініціалізувати це.

makes?: any[];

8

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

makes: any[] = [];

6

Починаючи з TypeScript 2.7.2, вам потрібно ініціалізувати властивість у конструкторі, якщо воно не було призначене в точці оголошення.

Якщо ви приїжджаєте з Vue, ви можете спробувати наступне:

  • Додайте "strictPropertyInitialization": trueдо вашого tsconfig.json

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

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

4

Під час оновлення за допомогою typecript@2.9.2, його компілятор дотримується суворих правил для оголошення типу масиву всередині конструктора класу компонентів.

Для виправлення цієї проблеми або змініть код, де оголошено в коді, або уникайте компілятору, щоб додати властивість "strictPropertyInitialization": false у файл "tsconfig.json" і запустити знову npm start.

Кутова веб-розробка та розробка мобільних додатків ви можете зайти на www.jtechweb.in


3

Чи не можете ви просто використати певне твердження про призначення? (Див. Https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#definite- assignment- assertions )

тобто оголошення майна як makes!: any[]; The! запевняє машинопис, що обов’язково буде значення під час виконання.

На жаль, я не пробував це в angular, але це чудово працювало для мене, коли у мене була така сама проблема в React.


Працюю з усіма версіями, оскільки вона є в офіційній документації, і я спробував. ДЯКУЮ!!
Hussein Akar

3

Отримати цю помилку під час додавання Node у моєму проекті Angular -

TSError:? Неможливо скомпілювати TypeScript: (шлях) /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",
    ...
}

Посилання на посилання - https://www.ryadel.com/en/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 okрядки нижчеgetMakes закінчення або якщо це getMakesне вдається, буде видано помилку компіляції. Інакше ваш додаток вийде з ладу.

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

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

2. Ви можете припустити, що він ніколи не провалиться і що ви ніколи не спробуєте отримати до нього доступ до ініціалізації, написавши код нижче (ризиковано!). Тож компілятор не подбає про це.

makes!: any[]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.