2017-08-24 13 views
2

Zuweisen (oder zu bestätigen) never am Ende einer Funktion ist eine Technik, die in Typescript verwandt wird, um erschöpfende Überprüfungen bei Kompilierungszeit zu erzwingen.Vollständigkeitsprüfungen ohne explizite Zeichenfolgen

Damit der Compiler dies erkennt, müssen jedoch explizite Zeichenfolgen überprüft werden, um festzustellen, ob die Funktion vor der Zuweisung/Assertion von never definitiv zurückgibt.

Wäre es möglich, eine Art typisierte Variation von Object.freeze einzuführen, die nur für Objektliterale und weiter oben in der Kette funktioniert, so dass etwas wie das Folgende getan werden könnte?

Noch besser, gibt es eine Möglichkeit, eine Schnittstelle zu schaffen, in der die Schlüssel automatisch die von jeder von Action.type (in diesem Beispiel) sind? Wenn das der Fall wäre - actionMap könnte einfach als diese Schnittstelle deklariert werden, was die Prüfung bei compiletime erzwingen würde.

Beide sind Lösungen für das gleiche Problem ... nur eine diskriminierte Union gegeben, ist es möglich, Vollständigkeitsüberprüfungen wie diese bei compiletime durchzuführen, ohne explizite Strings in der Funktion verwenden zu müssen?

interface Increment { 
    type: 'increment' 
} 

interface Decrement { 
    type: 'decrement' 
} 

type Action = Increment | Decrement 

const inc: Increment = { type: 'increment' }; 
const dec: Decrement = { type: 'decrement' }; 

//this would be a typescript variation 
const actionMap = Object.freeze({ 
    [inc.type]: n => n + 1, 
    [dec.type]: n => n-1 
}); 


function doAction(action: Action, val: number): number { 

    if(actionMap[action.type]) { 
     return actionMap[action.type](val); 
    } 

    //this would error at compile time if the above checked failed 
    const _exhaustiveCheck: never = action; 
} 

console.log(doAction(inc, 1)); 
console.log(doAction(dec, 1)); 
+0

Nur um klar zu sein. Sie möchten überprüfen, dass actionMap einen Wert für alle "type" -Werte in der diskriminierten Union "Action" hat. Ist das richtig? –

+0

ja! Stimmt :) – davidkomer

Antwort

3

Es gibt eine ziemlich direkte Möglichkeit, eine Karte zu erstellen, die garantiert, dass sie für jeden Fall in einer diskriminierten Union einen Wert hat. Sie müssen es einfach so einstellen, dass der Typ seiner Schlüssel der diskriminierte Union-Identifier ist.

type ActionMap = { 
    [P in Action["type"]]: (val:number)=>number 
}; 

Anschließend können Sie diese Schnittstelle implementieren, die so etwas wie folgt aussehen:

var map: ActionMap = { 
    decrement: n => n - 1, 
    increment: n=> n + 1 
} 

bearbeiten: Nach einer Reihe von Herumspielen fand ich eine wesentlich vielseitiger und leistungsfähige Lösung, die Sie nicht können Geben Sie nur die Schlüssel der diskriminierten Vereinigungswerte ein, aber Sie können auch die Nutzlast eingeben.

Zuerst: Definieren Sie Ihre Union in Form von Schlüssel: Typ Paare. (Ich denke, das sauberer ist sowieso zu lesen)

type Actions = { 
    "increment": { incrementValue: number } 
    "decrement": { decrementValue: number } 
} 

Zweite: Erstellen Sie eine Aktion diskriminierter Union von dieser Karte. Dies ist nicht der klarste Code der Welt. Für jedes Schlüsselwertpaar in erstellen Sie einen neuen Typ, indem Sie einen Typwert {type:key} hinzufügen und dann alle diese Typen zusammenfassen, um Ihre Discriminated Union zu erstellen.

type Action = { 
    [P in keyof Actions]: { type: P } & ActionsMap[P] 
}[keyof Actions]; 

Dritte: einen Typ für Ihre Karte erstellen

type ActionsMap = { 
    [P in keyof Actions]: (val:number,action:Actions[P])=>number 
} 

Forth: Genießen Sie Ihren ganz sicher Aktion/Reduzierer Karte geben!

const map:ActionsMap = { 
    decrement: (val, action) => val + action.decrementValue, 
    increment: (val, action) => val + action.incrementValue, 
} 

Messewarnung. Dies setzt die Grenzen dessen, was die Typoskript-Definition leisten kann, sehr in die Höhe und ich wurde persönlich gebissen, indem ich mich auf einige der Randbedingungen von Typoskripten verließ, nur um sie in der nächsten Version ändern zu lassen.

Verwandte Themen