2017-12-19 2 views
0

Ist es möglich, eine Mapped Art zu schreiben, die eine Klasse in eine Schnittstelle verwandelt minus die Methoden der Klasse oder irgendwelche zum prototype zugeordneten Eigenschaften. EG,Typoskript: Mapped Arten: Klasse Schnittstelle ohne Methoden

class Dog { 
    name: string; 
    age: number; 
    bark() {} 
    get dogYears(): number { 
     return this.age * 7; 
    } 
} 

type InterfaceOf<T> = { /* ??? */ }; 
type IDog = InterfaceOf<Dog>; 
// equivalent to 
interface IDog { 
    name: string; 
    age: number; 
} 

Warum muss ich dies tun wollen? Ich bin auf der Suche nach json Objekte in Klassen „deserialisieren“. ZB führe ich eine Abfrage aus, um Hunde aus der Datenbank zu holen, danach möchte ich sie in Klassenobjekte instanziieren, vielleicht unter Verwendung der class-transformer Bibliothek.

function queryDogs(): Promise<{ name: string, age: string }[]>; 
function deserialize<T>(cls: (new() => T), input: InterfaceOf<T>): T; 
function deserialize<T>(cls: (new() => T), inputs: InterfaceOf<T>[]): T[]; 

class Dog { 
    @Type(() => String) 
    name: string; 
    @Type(() => Number) 
    age: number; 
    bark() {} 
    get dogYears(): number { 
     return this.age * 7; 
    } 
} 

const dbDogs = await queryDogs(); 
const dogs: Dog[] = deserialize(Dog, dogs); 

Es wäre schön, wenn die deserialize Funktion weiß, ob die Eingabe die richtige Form war deserialisiert in die Dog-Klasse werden. Ich hatte gehofft, es an der Dog Klasse aussehen könnte, die ihm gegeben ist, es in die entsprechende Schnittstelle zu verwandeln.

Antwort

6

Schnittstelle basierend auf der Klasse

Sie direkt über eine Schnittstelle aus einer Klasse in Typoskript erzeugen:

interface DogLike extends Dog { 

} 

Die Angular Gemeinde aus aller das ist, aber hüte dich vor some warnings about using classes as interfaces.

Die Schnittstelle, die dies für Sie erzeugen würde würde Eigenschaften und Methoden sind:

interface DogLike { 
    name: string; 
    age: number; 
    bark(): void; 
    dogYears: number; 
} 

Mapped Typ Madness

Jetzt können Sie do something really clever/complex/mad with mapped types, based on the mapped types found in this article.

type Remove<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T]; 
type RemoveProperty<T, K extends keyof T> = { [P in Remove<keyof T, K>]: T[P] }; 

type PartDog = RemoveProperty<DogLike, 'bark' | 'dogYears'>; 

Dies nimmt die DogLike Schnittstelle und entfernt bark und dogYears.

Ich habe dies wie Sie erwähnt, Mapping-Typen enthalten. Es ist jedoch eine wahnsinnige Lösung.

Schnittstelle

Meine empfohlene Lösung, wäre aa einfache Schnittstelle, und vielleicht eine, die überhaupt nicht nach Hunden gestattet, da die Eigenschaften allgemeinere sind:

interface NamedLivingOrganism { 
    name: string; 
    age: number; 
} 

Okay, können Sie Nenne es nicht genau so. Jedoch ist einfach am besten und wenn Sie kommen, um entweder die Dog Klasse oder die Schnittstelle zu ändern, die zu irgendeinem Zeitpunkt in der Zukunft lose darauf basiert, wird sich die einfache Schnittstelle als der beste Weg erweisen, um darzustellen, was Sie brauchen.

+0

Danke für die detaillierte Antwort und die Warnung. Ich habe meine Frage mit einem Beispiel aktualisiert, wie ich es benutzen könnte. Ich habe das Gefühl, dass mein Anwendungsfall nicht ganz in dieses Warnszenario fällt. Vielleicht sollten Typoskript-Dekoratoren auf diese Weise ähnliche Warnungen erhalten? – sparebytes

+0

Ich würde auch gerne vorschlagen, dass es auch die 'Wählen Sie 'Ansatz, der als der' Remove' Ansatz fast so schmerzhaft ist. Ein weiteres Problem mit den 'Pick'- und' Remove'-Ansätzen ist, dass sie für verschachtelte Klassen zusammenbrechen, zB wenn die 'Hund'-Klasse eine 'Eigentümer'-Eigenschaft von' Mensch' hat – sparebytes

Verwandte Themen