2017-04-15 4 views
0

Ich war dabei, ein Problem auf GitHub für diese, aber ich dachte, ich würde hier zuerst fragen.Typescript Typ Wächter durch in Operator

Ich arbeite an einem Komponentenentitätssystem für ein Spiel, das ich mit Typoskript schreibe. Komponenten-Entity-Systeme in Javascript und (soweit ich das beurteilen kann) Typenskript neigen dazu, nicht sehr typsicher zu sein, und ich habe eine Idee, um das zu beheben.

Mein aktueller Plan ist es, jedes System, das von einer Anzahl von Komponenten abhängig ist, einen Entitätstyp verfügbar zu machen, der eine Reihe von Eigenschaften hat, welche Entitäten dieses System verarbeiten sollte. Ich werde dann an einem zentralen Ort alle verschiedenen Entity-Typen in einem kombinierten Entity-Union-Typ sammeln.

export type Entity = 
    CameraManagerEntity | 
    CollisionManagerEntity | 
    HoleManagerEntity | 
    ParentManagerEntity | ... 

Dann in einem System, würde Ich mag die Lage sein, zu behaupten, dass einige Eigenschaften auf der Einheit sind und die Typoskript ableiten, dass, weil die einzige Art in der Union, die hat diese Eigenschaft auf es die Art ist, dass Mein System exportiert, dann muss es der exportierte Typ sein.

Zum Beispiel, sagen die CameraManager

exportiert
interface CameraManagerEntity { 
    foo: boolean, 
    bar: number 
} 

Und kein anderer Typ in meiner Entity Union hat einen foo Parameter. Meine Erwartung ist, dass, wenn ich eine Instanz der Entity-Union habe, eine if-Anweisung, die behauptet, dass "foo" in der Instanz ist, ausreichen sollte, um auf die Bar der Instanz ohne einen Typfehler zuzugreifen.

function processEntity(entity: Entity) { 
    if ("foo" in entity) { 
     return entity.bar; // <-- Type error. 
    } 
} 

Fehle ich etwas? Ich denke, in einer idealen Welt sollte der Compiler genügend Informationen haben, um zu wissen, dass mein Entity-Objekt eine CameraManagerEntity ist, von der es stammt. Es scheint, dass das, was ich vorschlage, nicht funktioniert, da das Typoskript heute existiert. Gibt es einen besseren Weg, um das zu erreichen, was ich versuche? Danke im Voraus.

Edit: Ich bin bewusst von benutzerdefinierten Typ Wachen, wäre es einfach schön, nicht den Typ Wachen manuell zu schreiben, wie ich denke, der Compiler sollte alle Informationen bereits haben.

Antwort

1

Was Sie wollen, ist fast wie ein Tagged Union Type wandte sich von innen nach außen. Bei einem Tag-Unionstyp teilen sich alle Member ein gemeinsames Feld, und TypeScript unterscheidet, indem es den Wert dieses Feldes überprüft (normalerweise mit switch). In Ihrem aktuellen Design unterscheiden sich die Mitglieder des Unionstyps jedoch durch das Vorhandensein eindeutiger Felder.

kam ich mit einer generischen Art Wache, die ein entity gegen einen Typen überprüft, um das Vorhandensein einer Eigenschaft:

if (hasKeyOf<CameraManagerEntity>(entity, 'camera')) { 
    return entity.camera; 
} 

Hier ist das vollständige Beispiel:

interface CameraManagerEntity { 
    camera: string; 
} 

interface CollisionManagerEntity { 
    collision: string; 
} 

type Entity = CameraManagerEntity | CollisionManagerEntity; 

// Generic type guard 
function hasKeyOf<T>(entity: any, key: string): entity is T { 
    return key in entity; 
} 

function processEntity(entity: Entity) { 
    if (hasKeyOf<CameraManagerEntity>(entity, 'camera')) { 
    return entity.camera; 
    } else if (hasKeyOf<CollisionManagerEntity>(entity, 'collision')) { 
    return entity.collision; 
    } 
} 

Try it in TypeScript Playground

Sie könnten jedoch die Verwendung von Tagged Unionstypen für Ihr Entitätssystem erwägen, die ergonomischer sein könnten:

interface CameraManagerEntity { 
    kind: 'CameraManager'; 
    camera: string; 
} 

interface CollisionManagerEntity { 
    kind: 'CollisionManager'; 
    collision: string; 
} 

type Entity = CameraManagerEntity | CollisionManagerEntity; 

function processEntity(entity: Entity) { 
    switch (entity.kind) { 
    case ('CameraManager'): return entity.camera; 
    case ('CollisionManager'): return entity.collision; 
    } 
} 

Try it in TypeScript Playground

+0

Ich landete etwas zu tun, sehr ähnlich wie diese auf.Ich bin immer noch der Meinung, dass ein schlauer Compiler in der Lage sein sollte, herauszufinden, welcher Typ verwendet wird, oder zumindest die Typen in der Union auf Basis des in-Operators einzugrenzen, doch jetzt reicht das Schreiben von Typwächtern aus. Danke für deine Antwort. – Devagamster