angular - Egenskapen '...' har ingen initialverdi og er ikke definitivt tildelt i konstruktøren
i min Angular-app har jeg en komponent:
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);
}
}
men i "makes"-egenskapen har jeg en feil. Jeg vet ikke hva jeg skal gjøre med det...
Svar #1
Gå bare til tsconfig.json og sett
"compilerOptions": {
"strictPropertyInitialization": false,
...
}
å bli kvitt kompilasjonsfeilen.
Ellers må du initialisere alle variablene dine, noe som er litt irriterende
Svar #2
Jeg tror du bruker den nyeste versjonen av TypeScript. Vennligst se seksjonen «Strict Class Initialization» i link.
Det er to måter å fikse dette på:
A. Hvis du bruker VSCode, må du endre TS-versjonen som redigereren bruker.
B. Bare initialiser arrayen når du erklærer den
makes: any[] = [];
eller inne i konstruktøren:
constructor(private makeService: MakeService) {
// Initialization inside the constructor
this.makes = [];
}
Svar #3
Det er fordi TypeScript 2.7 inkluderer strenge klassekontroller der alle egenskapene må initialiseres i konstruktøren. En løsning er å legge til ! som et postfix til variabelnavnet:
makes!: any[];
Svar #4
Vi kan få meldingen Property has no initializer and is not definitely assigned in the constructor når vi legger til noen konfigurasjon i tsconfig.json-filen for å få et Angular-prosjekt kompilert i strict mode:
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"alwaysStrict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
Faktisk klager kompilatoren deretter på at en medlemsvariabel ikke er definert før den brukes.
For et eksempel på en medlemsvariabel som ikke er definert ved kompileringstid, en medlemsvariabel som har en @Input direktiv:
@Input() userId: string;
Vi kunne stilne kompilatoren ved å oppgi at variabelen kan være valgfri:
@Input() userId?: string;
Men da måtte vi håndtere tilfellet der variabelen ikke er definert, og fylle kildekoden med noen slike uttalelser:
if (this.userId) {
} else {
}
I stedet, ved å vite at verdien av denne medlemsvariabelen ville bli definert i tide, det vil si at den ville bli definert før den ble brukt, kan vi fortelle kompilatoren at den ikke trenger å bekymre seg for at den ikke er definert.
Måten å fortelle dette til kompilatoren på, er å legge til ! definite assignment assertion-operatoren, som i:
@Input() userId!: string;
Nå forstår kompilatoren at denne variabelen, selv om den ikke er definert ved kompileringstidspunktet, skal defineres under kjøring, og i tide, før den brukes.
Det er nå opp til applikasjonen å sikre at denne variabelen er definert før den brukes.
Som en ekstra beskyttelse kan vi påstå at variabelen blir definert før vi bruker den.
Vi kan slå fast at variabelen er definert, det vil si at den nødvendige input-bindingen faktisk ble gitt av den kallende konteksten:
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();
}
Når man vet at variabelen er definert, kan variabelen nå brukes:
ngOnChanges() {
this.userService.get(this.userId)
.subscribe(user => {
this.update(user.confirmedEmail);
});
}
Merk at ngOnInit-metoden blir kalt etter at forsøk på inndatabindinger har blitt gjort, dette selv om ingen faktisk input ble gitt til bindingene.
Mens ngOnChanges-metoden kalles etter forsøket på inputbindinger, og bare hvis det faktisk ble gitt input til bindingene.
Svar #5
Gå til din tsconfig.json-fil og endre egenskapen:
"noImplicitReturns": false
og deretter legg til
"strictPropertyInitialization": false
under "compilerOptions"-egenskapen.
Din tsconfig.json-fil bør se slik ut:
{
...
"compilerOptions": {
....
"noImplicitReturns": false,
....
"strictPropertyInitialization": false
},
"angularCompilerOptions": {
......
}
}
Håper dette vil hjelpe !!
Lykke til
Svar #6
Feilen er legitim og kan forhindre at appen din krasjer. Du skrev makes som et array, men det kan også være udefinert.
Du har 2 alternativer (i stedet for å deaktivere TypeScripts grunn til å eksistere...):
1. I ditt tilfelle er det best å skrive makes som muligens udefinert.
makes?: any[]
// or
makes: any[] | undefined
Så kompilatoren vil informere deg hver gang du prøver å få tilgang til makes om at det kan være udefinert. Ellers, hvis // <-- Not ok-linjene nedenfor ble kjørt før getMakes ble ferdig eller hvis getMakes mislyktes, ville appen din krasjet og en kjøretidsfeil ville blitt utløst. Det er definitivt ikke det du ønsker.
makes[0] // <-- Not ok
makes.map(...) // <-- Not ok
if (makes) makes[0] // <-- Ok
makes?.[0] // <-- Ok
(makes ?? []).map(...) // <-- Ok
2. Du kan anta at det aldri vil mislykkes og at du aldri vil prøve å få tilgang til det før initialisering ved å skrive koden nedenfor (risikabelt!). Så kompilatoren vil ikke ta seg av det.
makes!: any[]
Mer spesifikt,
Koden din sitt design trenger forbedring. Best praksis fraråder bruk av lokalt definerte og endringsbare variabler. En mer effektiv tilnærming innebærer å håndtere datalagring innenfor en tjeneste:
- For å sikre null/undefined-sikkerhet,
- Å faktorisere kode (inkludert skriving, lastetilstand og feil),
- For å kontrollere unødvendig ny-henting på tvers av komponenter.
Her er et illustrerende eksempel på konseptet jeg foreslår. Vennligst merk at jeg ikke har testet det, og det er rom for ytterligere forbedringer.
type Make = any // Type it
class MakeService {
private readonly source = new BehaviorSubject<Make[] | undefined>(undefined);
loading = false;
private readonly getMakes = (): Observable<Make[]> => {
/* ... your current implementation */
};
readonly getMakes2 = () => {
if (this.source.value) {
return this.source.asObservable();
}
return new Observable(_ => _.next()).pipe(
tap(_ => {
this.loading = true;
}),
mergeMap(this.getMakes),
mergeMap(data => {
this.source.next(data);
return data;
}),
tap(_ => {
this.loading = false;
}),
catchError((err: any) => {
this.loading = false;
return throwError(err);
}),
);
};
}
@Component({
selector: 'app-vehicle-form',
template: `
<div *ngIf="makeService.loading">Loading...</div>
<div *ngFor="let vehicule of vehicules | async">
{{vehicle.name}}
</div>
`,
styleUrls: ['./vehicle-form.component.css']
})
export class VehicleFormComponent implements OnInit {
constructor(public makeService: MakeService) {}
readonly makes = this.makeService.getMakes2().pipe(
tap(makes => console.log('MAKES', makes))
);
readonly vehicules = this.makes.pipe(
map(make => make/* some transformation */),
tap(vehicule => console.log('VEHICLE', vehicule)),
);
ngOnInit() {
this.makes.subscribe(makes => {
console.log('MAKES', makes);
});
}
}
Svar #7
det finnes mange løsninger
demokode
class Plant {
name: string;
// ❌ Property 'name' has no initializer and is not definitely assigned in the constructor.ts(2564)
}
løsninger
- legg til 'undefined'-type
class Plant {
name: string | undefined;
}
- legg til definitiv tildelingspåstand
class Plant {
name!: string;
}
- deklarer med startverdi 👍
class Plant {
name: string = '';
}
- bruk konstruktøren med en startverdi 👍
class Plant {
name: string;
constructor() {
this.name = '';
}
}
- bruk konstruktøren og init-verdien via parametere 👍
class Plant {
name: string;
constructor(name: string) {
this.name = name ?? '';
}
}
- forkortelse for
5👍
class Plant {
constructor(public name: string = name ?? '') {
//
}
}
tsconfig.json
ikke anbefalt
{
"compilerOptions": {
+ "strictPropertyInitialization": false,
- "strictPropertyInitialization": true,
}
}
dommere
https://www.typescriptlang.org/docs/handbook/2/classes.html#--strictpropertyinitialization
Svar #8
Gå til tsconfig.json
legg til "strictPropertyInitialization": false, i "compilerOptions":
Svar #9
Oppdatering for 2021:
det finnes en egenskap som heter "strictPropertyInitialization"
Bare gå til tsconfig.json og sett
"strict": false
å bli kvitt kompilasjonsfeilen.
Ellers må du initialisere alle variablene dine, noe som er litt irriterende.
årsaken til denne feilen er :
- TypeScript er en slags mer sikker språk sammenlignet med JavaScript.
- selv om denne sikkerheten forbedres ved å aktivere streng funksjon. Så hver gang du initialiserer en variabel, ønsker Typescript at de skal tilordne en verdi.
Svar #10
Du må enten deaktivere --strictPropertyInitialization som Sajeetharan refererte til, eller gjøre noe slik for å tilfredsstille initialiseringskravet:
makes: any[] = [];
Svar #11
Du kan også gjøre følgende hvis du virkelig ikke vil initialisere det.
makes?: any[];
Svar #12
En bedre tilnærming vil være å legge til utropstegnet på slutten av variabelen som du er sikker på ikke skal være undefined eller null, for eksempel hvis du bruker en ElementRef som må lastes fra malen og ikke kan defineres i konstruktøren, gjør noe som nedenfor
class Component {
ViewChild('idname') variable! : ElementRef;
}
Svar #13
Hvis du vil initialisere et objekt basert på et grensesnitt kan du initialisere det tomt med følgende setning.
myObj: IMyObject = {} as IMyObject;
Svar #14
Sett et spørsmålstegn (?) etter makes-variabelen.
makes?: any[];
vehicle = {};
constructor(private makeService: MakeService) { }
Det burde fungere nå. Jeg bruker Angular 12, og det fungerer i koden min.
Svar #15
hvis du ikke vil endre tsconfig.json, kan du definere klassen din slik:
class Address{
street: string = ''
}
eller, du kan også gå frem på denne måten:
class Address{
street!: string
}
Ved å legge til et utropstegn "!" etter variabelnavnet ditt, vil Typescript være sikker på at denne variabelen ikke er null eller undefined.
Svar #16
Fra og med TypeScript 2.7.2 må du initialisere en egenskap i konstruktøren hvis den ikke ble tildelt på tidspunktet for deklarasjonen.
Hvis du kommer fra Vue, kan du prøve følgende:
Legg til
"strictPropertyInitialization": truei din tsconfig.jsonHvis du er misfornøyd med å deaktivere det, kan du også prøve dette
makes: any[] | undefined. Å gjøre dette krever at du får tilgang til egenskapene med nullsjekk (?.)-operatoren, dvs.this.makes?.length- Du kan like godt prøve
makes!: any[];, dette forteller TS at verdien vil bli tildelt under kjøring.
Svar #17
Får denne feilen når jeg legger til Node i mitt Angular-prosjekt -
TSError: ? Kan ikke kompilere TypeScript: (path)/base.api.ts:19:13 - feil TS2564: Egenskapen 'apiRoot Path' har ingen initialisering og er ikke definitivt tilordnet i konstruktøren.
privat apiRootPath: string;
Løsning -
La til "strictPropertyInitialization": false i 'compilerOptions' i tsconfig.json.
min package.json -
"dependencies": {
...
"@angular/common": "~10.1.3",
"@types/express": "^4.17.9",
"express": "^4.17.1",
...
}
Ref URL - https://www.ryadel.com/en/ts2564-ts-property-has-no-initializer-typescript-error-fix-visual-studio-2017-vs2017/
Svar #18
i tsconfig.json-filen, inne i "compilerOptions" legg til :
"strictPropertyInitialization": false,


