angular - Egenskapen '...' har ingen initialisering och har inte definitivt tilldelats i konstruktorn
i min Angular-app har jag 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 egenskapen "makes" har jag ett misstag. Jag vet inte vad jag ska göra med det...
Svar #1
Gå bara till tsconfig.json och ställ in
"compilerOptions": {
"strictPropertyInitialization": false,
...
}
att bli av med kompileringsfelet.
Annars behöver du initialisera alla dina variabler vilket är lite irriterande
Svar #2
Jag tror att du använder den senaste versionen av TypeScript. Vänligen se avsnittet "Strict Class Initialization" i link.
Det finns två sätt att fixa detta:
A. Om du använder VSCode behöver du ändra TS-versionen som editorn använder.
B. Initiera bara arrayen när du deklarerar den
makes: any[] = [];
eller i konstruktören:
constructor(private makeService: MakeService) {
// Initialization inside the constructor
this.makes = [];
}
Svar #3
Det är eftersom TypeScript 2.7 inkluderar en strikt klasskontroll där alla egenskaper ska initialiseras i konstruktorn. En lösning är att lägga till ! som ett postfix till variabelnamnet:
makes!: any[];
Svar #4
Vi kan få meddelandet Property has no initializer and is not definitely assigned in the constructor när vi lägger till viss konfiguration i tsconfig.json-filen för att få ett Angular-projekt kompilerat i strikt läge:
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"alwaysStrict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
Faktiskt klagar sedan kompilatorn på att en medlemsvariabel inte är definierad innan den används.
Som ett exempel på en medlemsvariabel som inte definieras vid kompileringstid, en medlemsvariabel med en @Input-direktiv:
@Input() userId: string;
Vi kunde tysta kompilatorn genom att ange att variabeln kan vara valfri:
@Input() userId?: string;
Men då skulle vi behöva hantera fallet där variabeln inte är definierad, och göra källkoden rörig med sådana uttalanden:
if (this.userId) {
} else {
}
Istället, eftersom värdet av denna medlemsvariabel skulle vara definierad i tid, det vill säga, det skulle vara definierad innan den används, kan vi tala om för kompilatorn att inte oroa sig för att den inte är definierad.
Sättet att tala om detta för kompilatorn är att lägga till ! definite assignment assertion-operatorn, som i:
@Input() userId!: string;
Nu förstår kompilatorn att denna variabel, även om den inte är definierad vid kompileringstid, ska definieras vid körningstid och i tid innan den används.
Det är nu upp till applikationen att säkerställa att denna variabel är definierad innan den används.
Som ett extra skydd kan vi säkerställa att variabeln definieras innan vi använder den.
Vi kan hävda att variabeln är definierad, det vill säga att den nödvändiga inmatningsbindningen faktiskt tillhandahölls av den anropande kontexten:
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();
}
Eftersom variabeln var definierad kan variabeln nu användas:
ngOnChanges() {
this.userService.get(this.userId)
.subscribe(user => {
this.update(user.confirmedEmail);
});
}
Observera att ngOnInit-metoden kallas efter att input-bindningarna har försökt, detta även om ingen faktisk input gavs till bindningarna.
Medan ngOnChanges-metoden kallas efter att försöket med indata-bindningar gjorts, och endast om faktisk indata tillhandahölls till bindningarna.
Svar #5
Gå till din tsconfig.json-fil och ändra egenskapen:
"noImplicitReturns": false
och sedan lägg till
"strictPropertyInitialization": false
under "compilerOptions"-egenskapen.
Din tsconfig.json-fil bör se ut så här:
{
...
"compilerOptions": {
....
"noImplicitReturns": false,
....
"strictPropertyInitialization": false
},
"angularCompilerOptions": {
......
}
}
Hoppas detta hjälper !!
Lycka till
Svar #6
Felet är legitimt och kan förhindra att din app kraschar. Du skrev makes som en array men det kan också vara odefinierat.
Du har 2 alternativ (istället för att inaktivera TypeScripts anledning till att existera…):
1. I ditt fall är det bästa att skriva makes som möjligtvis odefinierad.
makes?: any[]
// or
makes: any[] | undefined
Så kompilatorn kommer att informera dig när du försöker komma åt makes att det kan vara odefinierat. Annars, om // <-- Not ok raderna nedan kördes innan getMakes avslutades eller om getMakes misslyckades, skulle din app krascha och ett körtidsfel skulle uppstå. Det är definitivt inte vad du vill.
makes[0] // <-- Not ok
makes.map(...) // <-- Not ok
if (makes) makes[0] // <-- Ok
makes?.[0] // <-- Ok
(makes ?? []).map(...) // <-- Ok
2. Du kan anta att det aldrig kommer att misslyckas och att du aldrig försöker komma åt det innan initialisering genom att skriva koden nedan (riskabelt!). Så kompilatorn kommer inte att ta hand om det.
makes!: any[]
Mer specifikt,
Din kods design kräver förbättring. Bästa praxis avråder från att använda lokalt definierade och föränderliga variabler. En mer effektiv metod innebär att hantera datalagring inom en tjänst:
- För att säkerställa null/undefined-säkerhet,
- Att faktorisera kod (inklusive inmatning, laddningstillstånd och fel),
- För att kontrollera onödig omhämtning över komponenter.
Här är ett illustrativt exempel på det koncept jag föreslår. Observera att jag inte har testat det, och det finns utrymme för ytterligare förbättring.
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 finns många lösningar
demokod
class Plant {
name: string;
// ❌ Property 'name' has no initializer and is not definitely assigned in the constructor.ts(2564)
}
lösningar
- lägg till 'undefined'-typ
class Plant {
name: string | undefined;
}
- lägg till definitiv tilldelningspåstående
class Plant {
name!: string;
}
- deklarera med startvärde 👍
class Plant {
name: string = '';
}
- använd konstruktorn med ett startvärde 👍
class Plant {
name: string;
constructor() {
this.name = '';
}
}
- använd konstruktorn och initiera värdet med parametrar 👍
class Plant {
name: string;
constructor(name: string) {
this.name = name ?? '';
}
}
- kortform av
5👍
class Plant {
constructor(public name: string = name ?? '') {
//
}
}
tsconfig.json
inte rekommenderat
{
"compilerOptions": {
+ "strictPropertyInitialization": false,
- "strictPropertyInitialization": true,
}
}
domare
https://www.typescriptlang.org/docs/handbook/2/classes.html#--strictpropertyinitialization
Svar #8
Gå till tsconfig.json
lägg till "strictPropertyInitialization": false, i "compilerOptions":
Svar #9
Uppdatering för 2021:
det finns en egenskap som heter "strictPropertyInitialization"
Gå bara till tsconfig.json och ställ in
"strict": false
att bli av med kompileringsfelet.
Annars behöver du initialisera alla dina variabler vilket är lite irriterande.
orsaken bakom detta fel är :
- TypeScript är en slags mer säker språk jämfört med JavaScript.
- även om denna säkerhet förbättras genom att aktivera strikt funktion. Så varje gång du initialiserar en variabel vill TypeScript att de tilldelas ett värde.
Svar #10
Du behöver antingen inaktivera --strictPropertyInitialization som Sajeetharan hänvisade till, eller göra något liknande detta för att uppfylla initialiseringskravet:
makes: any[] = [];
Svar #11
Du kan också göra följande om du verkligen inte vill initiera det.
makes?: any[];
Svar #12
Ett bättre tillvägagångssätt skulle vara att lägga till utropstecknet i slutet av variabeln för vilken du är säker på att den inte kommer att vara undefined eller null, till exempel om du använder en ElementRef som behöver laddas från mallen och inte kan definieras i konstruktorn, gör något som nedan
class Component {
ViewChild('idname') variable! : ElementRef;
}
Svar #13
Om du vill initialisera ett objekt baserat på ett gränssnitt kan du initialisera det tomt med följande uttalande.
myObj: IMyObject = {} as IMyObject;
Svar #14
Sätt ett frågetecken (?) efter makes-variabeln.
makes?: any[];
vehicle = {};
constructor(private makeService: MakeService) { }
Det borde fungera nu. Jag använder Angular 12 och det fungerar i min kod.
Svar #15
om du inte vill ändra din tsconfig.json, kan du definiera din klass så här:
class Address{
street: string = ''
}
eller, du kan också fortsätta så här:
class Address{
street!: string
}
genom att lägga till ett utropstecken "!" efter ditt variabelnamn kommer Typescript att vara säker på att denna variabel inte är null eller undefined.
Svar #16
Från och med TypeScript 2.7.2 måste du initialisera en egenskap i konstruktorn om den inte tilldelades vid deklarationstillfället.
Om du kommer från Vue kan du prova följande:
Lägg till
"strictPropertyInitialization": truei din tsconfig.jsonOm du är missnöjd med att inaktivera det kan du också prova detta
makes: any[] | undefined. Att göra detta kräver att du använder egenskaperna med null-kontroll (?.) operatorn, dvsthis.makes?.length- Du kan lika gärna prova
makes!: any[];, detta säger till TS att värdet kommer att tilldelas vid körning.
Svar #17
Får detta fel vid tidpunkten för att lägga till Node i mitt Angular-projekt -
TSError: ? Kan inte kompilera TypeScript: (path)/base.api.ts:19:13 - fel TS2564: Egenskapen 'apiRoot Path' har ingen initialisering och tilldelas inte definitivt i konstruktorn.
privat apiRootPath: sträng;
Lösning -
Lagt till "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, inuti "compilerOptions" lägg till:
"strictPropertyInitialization": false,


