0 day streak
javascript / intermediate
Snippet

Enforcing Model Type Safety with Generic Base Components

Abstract directive classes in Angular allow shared state, common inputs/outputs, and lifecycle methods to be inherited across multiple editor components. Applying generic type constraints ensures that inheriting components strictly adhere to model requirements while preserving compile-time type checking.

snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { Directive, EventEmitter, Input, Output } from '@angular/core';
export interface BaseEntity {
id: string | number;
updatedAt: Date;
}
@Directive()
export abstract class BaseEditorComponent<T extends BaseEntity> {
@Input({ required: true }) entity!: T;
@Output() save = new EventEmitter<T>();
@Output() cancel = new EventEmitter<void>();
protected isDirty = false;
abstract validateEntity(model: T): boolean;
public handleSave(): void {
if (this.validateEntity(this.entity)) {
this.isDirty = false;
this.save.emit(this.entity);
}
}
public handleCancel(): void {
this.isDirty = false;
this.cancel.emit();
}
}
angular
Breakdown
1
@Directive()
Applies Angular's Directive decorator to enable dependency injection and property bindings on an abstract base class.
2
export abstract class BaseEditorComponent<T extends BaseEntity> {
Defines an abstract class parameterized by a generic type T constrained to BaseEntity implementations.
3
@Input({ required: true }) entity!: T;
Enforces a required strongly-typed input representing the entity model being edited.
4
abstract validateEntity(model: T): boolean;
Forces concrete child subclasses to implement domain-specific validation logic.
5
if (this.validateEntity(this.entity)) {
Executes polymorphism: delegates validation to the derived class before emitting save events.