Existential Types in TypeScript

Aus Haskell kennen wir die sogenannten ‚Existential Types‘. TypeScript bietet leider nicht von Haus aus, diese Funktionalität an. Demnach gibt es immer wieder Code wie diesen, der so nicht funktioniert:

type Tuple<T> = {
    left: T;
    right: T;
} 

const listOfTuples: Tuple<any>[] = [
    { left: "Its a string", right: "String as well" },
    { left: 1337, right: "This is not OK!!!"} // Here is no error, but should be one.
]

Der Code soll beim zweiten Array Element einen Fehler erzeugen, das passiert aber nicht, da any erlaubt ist und der TypeScript Compiler aktuell nicht weiß, dass propTwo vom Typ number sein soll. Um das zu lösen, braucht es Existential Types, welche wir über einen Umweg codieren müssen.

Fangen wir an, das Beispiel etwas umzubauen. Aus der Variable wird eine Funktion welche wir aus Mangel an besseren Ideen einfach getList nennen.

type Tuple<T> = {
    left: T,
    right: T,
}

const getList = (): Tuple<unknown>[] => {
    return [ /* TODO: Return actual tuples */ ];
}

Per Pseudocode ausgedrückt möchten wir nun einen Typ haben für den folgendes gilt:

type TupleCreator = <es exisiert ein R>(left: R, right: R) => Tuple<R>

Das können wir in TypeScript mit einem Typ ausdrücken, welcher eine Funktion darstellt (wie oben zu erkennen). Demnach lautet unser Typ wie folgt:

type TupleCreator = <R>(left: R, right: R) => Tuple<R>

Somit sieht der vollständige Code so aus:

type Tuple<T> = {
    left: T,
    right: T,
}

type TupleCreator = <R>(left: R, right: R) => Tuple<R>
const createTuple: TupleCreator = (left, right) => ({left, right})

const getList = (): Tuple<unknown>[] => {

    return [
        createTuple("Its a string", "String as well"),
        createTuple(1337, "This is not OK!!!") // 🥳 finally an error
    ]
}

Mit Hilfe des ‚TupleCreator‘ und der ‚createTuple‘ Funktion konnten wir einen Typ erzeugen, der uns genau das ursprüngliche Problem löst. Nämlich die Abhängigkeit der zwei Generics T (left und right). Denn für diese haben wir gesagt gilt, dass beide Identisch sein müssen, egal für welches T. Somit haben wir in einem einfachen Beispiel die Existential Types erfolgreich codiert.

2880cookie-checkExistential Types in TypeScript

Kommentar verfassen