Java Predicates in TypeScript

Jeder Java Entwickler sie, Predicates. Ein hilfreiches Features, welches mit Java 8 Einzug in das JDK fand. Es gibt viele sinnvolle Einsatz Gebiete dafür, z.B. das Abstrahieren von Validierungslogik uvm.

Heute möchte ich euch eine Möglichkeit zeigen, wie ihr die Predicates auch in TypeScript (sprich eure React, Angular, uvm. Anwendungen) integrieren könnt. Dazu orientiere ich mich am Java Standard, welcher das Interface für ein Predicate folgendermaßen beschreibt: https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html

Zu nächst können wir uns eine neue Datei anlegen, nennen wir sie einmal predicate.ts und fügen einen Typen ein. Nennen wir diesen TPredicate.

type TPredicate<T> = (value: T) => boolean;

Dieser Typ soll uns die Möglichkeit geben, zu beschreiben was eine Prädikat Funktion ist. Somit ist eine Prädikat Funktion definiert, als eine Funktion, welche uns einen Wahrheitswert (boolean) zurückgibt. Das Ergebnis ist abhängig vom Parameter (value), welcher in unserem Fall ein generischer Typ (T) ist.

Das Grundgerüst unserer Klasse könnte wie folgt aussehen

class Predicate<T> {
    constructor(private predicate: TPredicate<T>) { /* empty */ }

    /* API conform implementation follows */
}

Aufgrund der Tatsache, dass Java sogenannte Functional Interfaces bietet, müssen wir um das Problem herumarbeiten, welches daraus resultiert. Und zwar können wir nicht jede x-beliebige Funktion als Prädikat interpretieren. Dies müssen wir bedenken und können somit eine statische Methode hinzufügen, die uns genau dieses Problem löst.

class Predicate<T> {
    constructor(private predicate: TPredicate<T>) { /* empty */ }

    public static of = <T>(inputPredicate: Predicate<T> | TPredicate<T>): Predicate<T> => {
        return inputPredicate instanceof Predicate ? inputPredicate : new Predicate(inputPredicate);
    }

    /* API conform implementation follows */
}

Nach demselben Schema können wir nun die restlichen Methoden: and, negate und test hinzufügen. Diese sind aufgrund unserer Vorarbeit ziemliche selbstläufer und müssen lediglich nur noch korrekt typisiert werden.

class Predicate<T> {
    constructor(private predicate: TPredicate<T>) { /* empty */ }

    public static of = <T>(inputPredicate: Predicate<T> | TPredicate<T>): Predicate<T> => {
        return inputPredicate instanceof Predicate ? inputPredicate : new Predicate(inputPredicate);
    }

    public test = (value: T): boolean => this.predicate(value);

    public and = (otherPredicate: Predicate<T> | TPredicate<T>) =>
        Predicate.of((value: T) => this.test(value) && Predicate.of(otherPredicate).test(value));

    public or = (otherPredicate: Predicate<T> | TPredicate<T>) =>
        Predicate.of((value: T) => this.test(value) || Predicate.of(otherPredicate).test(value));

    public negate = () =>
        Predicate.of((value: T) => !this.test(value));
}

Die Einsatzmöglichkeiten sind natürlich damit nahe zu grenzenlos.

Wer sich das ganze Live ansehen möchte, kann dies auf TypeScript Playground natürlich tun.

Hier der Link zu einem Beispiel (Link to TypeScript Playground): Playground Link

1100cookie-checkJava Predicates in TypeScript

Kommentar verfassen