Bessere Typensicherheit mit eckigen generischen Komponenten
Verbessern Sie die Typensicherheit Ihrer Komponenten, ohne auf Flexibilität zu verzichten
Kürzlich musste ich in Angular eine Dropdown-Komponente erstellen, um einige benutzerdefinierte Stile und Verhaltensweisen darauf anzuwenden. Das fing ganz einfach an. Ich habe so etwas gemacht:
// dropdown.component.ts
@Component({
selector: 'app-dropdown',
templateUrl: './dropdown.component.html'
})
export class DropdownComponent {
@Input()
currentOption: any; // <- Yikes!
@Input()
options: any[]; // <- Yikes!
}
Ich dachte darüber nach, unknownstattdessen zu verwenden any, aber das machte mir mehr Probleme und es fühlte sich auch einfach wie „besser any“ an. Ich will meine Typen, verdammt!
Nun, es stellt sich heraus, dass Sie Ihrer Komponente tatsächlich einen generischen Typ geben können! Angular ist intelligent genug, um anhand der Verwendung zu erkennen, um welchen Typ es sich bei Ihrer Komponente handelt. Hier ist seine Anwendung:
// dropdown.component.ts
@Component({
selector: 'app-dropdown',
templateUrl: './dropdown.component.html'
})
export class DropdownComponent<T> {
@Input()
currentOption: T;
@Input()
options: T[];
}
// app.component.ts
type MyCustomType = { name: string, value: number };
type SomeOtherType = { title: string, value: string };
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
currentOption: MyCustomType = { name: 'foo', value: 42};
// Intentionally using wrong type
options: SomeOtherType = [
{
title: 'foo',
value: '42',
},
{
title: 'bar',
value: '13',
},
]
}
<!-- app.component.html -->
<app-dropdown
[value]="currentOption"
[options]="options" <!-- Error: not assignable to MyCustomType -->
>
</app-dropdown>
Bewegen Sie den Mauszeiger darüber <app-dropdown>und sehen Sie, was Intellisense Ihnen über Ihre Komponente sagt.
Nennen Sie mich einen Masochisten, aber ich liebe es, wenn mich Schreibmaschine anschreit, wenn ich einen Fehler mache. Besser als die Stimmen in meinem Kopf, die mein Hochstapler-Syndrom auslösen, wenn ich einen Laufzeitfehler erhalte!
Ein praktischer Anwendungsfall
Die Dropdown-Komponente muss weiterhin ihre Optionen anzeigen. Die Vorlage würde etwa wie folgt aussehen:
<!-- dropdown.component.html -->
<select>
<option *ngFor="let option of options">
{{ option.whatGoesHere? }} <!-- hmmmm.... -->
</option>
</select>
Um den Anforderungen unserer Dropdown-Komponente gerecht zu werden, können wir einen Typ wie den folgenden erstellen:
// dropdown.component.ts
export type DropdownOption<T> = {
text: string;
value: T;
}
@Component({
selector: 'app-dropdown',
templateUrl: './dropdown.component.html'
})
export class DropdownComponent<T> {
// ...
// dropdown.component.ts
@Component({
selector: 'app-dropdown',
templateUrl: './dropdown.component.html'
})
export class DropdownComponent<T> {
@Input()
value: DropdownOption<T>;
@Input()
options: DropdownOption<T>[];
}
<!-- dropdown.component.html -->
<select>
<option *ngFor="let option of options">
{{ option.text }}
</option>
</select>
Zurück zu der Stelle, an der wir unser currentOptionund verwendet haben availableOptions, erhalten wir nun die folgende Fehlermeldung:
<!-- app.component.html -->
<app-dropdown
[value]="currentOption" <!-- Error: not assignable to DropdownOption -->
[options]="options" <!-- Error: not assignable to DropdownOption[] -->
>
</app-dropdown>
type MyCustomType = { name: string, value: number };
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
currentOption: MyCustomType = { name: 'foo', value: 42};
options: MyCustomType[] = [
{
name: 'foo',
value: 42,
},
{
name: 'bar',
value: 13,
},
]
// ## NEW ##
get valueAsDropdownItem(): DropdownOption<MyCustomType> {
return this.toDropdownOption(this.currentOption);
}
// ## NEW ##
get optionsAsDropdownItems(): DropdownOption<MyCustomType>[] {
return this.options.map(option => this.toDropdownOption(option));
}
// ## NEW ##
toDropdownOption(item: MyCustomType): DropdownOption<MyCustomType> {
return {
title: item.name,
value: item,
}
}
}
<!-- app.component.html -->
<app-dropdown
[value]="valueAsDropdownItem"
[options]="optionsAsDropdownItems"
>
</app-dropdown>
Verweise
- Artikel über generische Komponenten von Damir's Corner ( Link )
- Repository mit endgültiger Implementierung

![Was ist überhaupt eine verknüpfte Liste? [Teil 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































