Statt für jedes Formular einen monolithischen Validator von Hand zu schreiben, behandelt dieses Muster Validatoren als erstklassige Werte, die von parametrisierten Factory-Funktionen erzeugt werden, und kombiniert sie mit einer Funktion höherer Ordnung composeAnd, die jedes nicht-null ValidationErrors-Objekt zu einem zusammenführt. Jede Factory schließt über ihre Konfiguration (eine Anzahl, einen Pfad zu einem Geschwister-Control) und liefert eine reine ValidatorFn zurück, sodass dasselbe minDistinctChars(4) über unabhängige Formulare mit unterschiedlichen Schwellenwerten wiederverwendet werden kann — und composeAnd funktioniert mit beliebig vielen Validatoren, ohne dass der Aufrufer wissen muss, wie viele gleichzeitig fehlgeschlagen sind.
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';function minDistinctChars(count: number): ValidatorFn {return (control: AbstractControl): ValidationErrors | null => {const value: string = control.value ?? '';const distinct = new Set(value.split('')).size;return distinct >= count ? null : { minDistinctChars: { required: count, actual: distinct } };};}function composeAnd(...validators: ValidatorFn[]): ValidatorFn {return (control: AbstractControl): ValidationErrors | null => {return validators.reduce<ValidationErrors | null>((acc, validate) => {const result = validate(control);return result ? { ...acc, ...result } : acc;}, null);};}function notEqualTo(otherControlPath: string): ValidatorFn {return (control: AbstractControl): ValidationErrors | null => {const sibling = control.parent?.get(otherControlPath);if (!sibling) return null;return control.value === sibling.value ? { notEqualTo: { path: otherControlPath } } : null;};}const passwordValidator = composeAnd(minDistinctChars(4), notEqualTo('username'));