Ich habe ein JSON-Objekt von einem Remote-REST-Server gelesen. Dieses JSON-Objekt verfügt über alle Eigenschaften einer Typoskriptklasse (beabsichtigt). Wie wandle ich das empfangene JSON-Objekt in einen Typ var um?
Ich möchte keine Typoskript-Variable füllen (dh einen Konstruktor haben, der dieses JSON-Objekt verwendet). Es ist groß und das Kopieren von Unterobjekten für Unterobjekte und Eigenschaften für Eigenschaften würde viel Zeit in Anspruch nehmen.
Update: Sie können es jedoch in eine Typoskript-Oberfläche umwandeln!
json
typescript
David Thielen
quelle
quelle
Antworten:
Sie können ein einfaches JavaScript-Ergebnis aus einer Ajax-Anforderung nicht einfach in eine prototypische JavaScript / TypeScript-Klasseninstanz umwandeln. Es gibt eine Reihe von Techniken, die im Allgemeinen das Kopieren von Daten umfassen. Sofern Sie keine Instanz der Klasse erstellen, verfügt sie über keine Methoden oder Eigenschaften. Es bleibt ein einfaches JavaScript-Objekt.
Wenn Sie sich nur mit Daten befassen, können Sie einfach eine Umwandlung in eine Schnittstelle durchführen (da es sich lediglich um eine Kompilierungszeitstruktur handelt). Dazu müssen Sie jedoch eine TypeScript-Klasse verwenden, die die Dateninstanz verwendet und Operationen mit diesen Daten ausführt.
Einige Beispiele zum Kopieren der Daten:
Im Wesentlichen würden Sie nur:
quelle
JSON.parse()
. Beides müsste noch getan werden, aber syntaktisch könnten sie kombiniert werden.Object.setPrototypeOf
Ich hatte das gleiche Problem und habe eine Bibliothek gefunden, die diese Aufgabe erfüllt: https://github.com/pleerock/class-transformer .
Es funktioniert so:
Es unterstützt verschachtelte Kinder, aber Sie müssen das Mitglied Ihrer Klasse dekorieren.
quelle
@Type
Anmerkungen). Diese Antwort verdient mehr Anerkennung.In TypeScript können Sie eine Typzusicherung über eine Schnittstelle und Generika wie folgt durchführen:
Wobei ILocationMap die Form Ihrer Daten beschreibt. Der Vorteil dieser Methode besteht darin, dass Ihr JSON möglicherweise mehr Eigenschaften enthält, die Form jedoch die Bedingungen der Schnittstelle erfüllt.
Ich hoffe das hilft!
quelle
Wenn Sie ES6 verwenden, versuchen Sie Folgendes:
Aber dieser Weg funktioniert leider nicht auf dem Nestobjekt.
quelle
Object.create(MyClass.prototype)
Umgehung des Konstruktors erstellt werden.Ich fand einen sehr interessanten Artikel über das generische Casting von JSON in eine Typescript-Klasse:
http://cloudmark.github.io/Json-Mapping/
Am Ende erhalten Sie folgenden Code:
quelle
TLDR: Ein Liner
Die detaillierte Antwort
Ich würde nicht den Object.assign-Ansatz empfehlen, da er Ihre Klasseninstanz unangemessen mit irrelevanten Eigenschaften (sowie definierten Abschlüssen) verunreinigen kann, die nicht in der Klasse selbst deklariert wurden.
In der Klasse, in die Sie deserialisieren möchten, würde ich sicherstellen, dass alle Eigenschaften definiert sind, die deserialisiert werden sollen (null, leeres Array usw.). Indem Sie Ihre Eigenschaften mit Anfangswerten definieren, legen Sie deren Sichtbarkeit offen, wenn Sie versuchen, Klassenmitglieder zu iterieren, denen Werte zugewiesen werden sollen (siehe Deserialisierungsmethode unten).
Im obigen Beispiel habe ich einfach eine Deserialisierungsmethode erstellt. In einem Beispiel aus der Praxis würde ich es in einer wiederverwendbaren Basisklasse oder Dienstmethode zentralisieren lassen.
Hier erfahren Sie, wie Sie dies in so etwas wie einem http bzw. ...
Wenn tslint / ide sich darüber beschwert, dass der Argumenttyp nicht kompatibel ist, wandeln Sie das Argument einfach in eckigen Klammern in denselben Typ um
<YourClassName>
. Beispiel:Wenn Sie Klassenmitglieder eines bestimmten Typs haben (auch bekannt als: Instanz einer anderen Klasse), können Sie diese über Getter / Setter-Methoden in typisierte Instanzen umwandeln lassen.
Das obige Beispiel deserialisiert sowohl acct als auch die Liste der Aufgaben in ihre jeweiligen Klasseninstanzen.
quelle
Angenommen, der JSON hat dieselben Eigenschaften wie Ihre Typoskriptklasse, müssen Sie Ihre Json-Eigenschaften nicht in Ihr Typoskriptobjekt kopieren. Sie müssen nur Ihr Typescript-Objekt erstellen, indem Sie die JSON-Daten im Konstruktor übergeben.
In Ihrem Ajax-Rückruf erhalten Sie eine Firma:
Damit das funktioniert:
1) Fügen Sie Ihrer Typescript-Klasse einen Konstruktor hinzu, der die JSON-Daten als Parameter verwendet. In diesem Konstruktor erweitern Sie Ihr json-Objekt mit jQuery wie folgt :
$.extend( this, jsonData)
. Mit $ .extend können die Javascript-Prototypen beibehalten werden, während die Eigenschaften des JSON-Objekts hinzugefügt werden.2) Beachten Sie, dass Sie dasselbe für verknüpfte Objekte tun müssen. Im Fall von Mitarbeitern im Beispiel erstellen Sie auch einen Konstruktor, der den Teil der JSON-Daten für Mitarbeiter übernimmt. Sie rufen $ .map auf, um json-Mitarbeiter in Typoskript-Mitarbeiterobjekte zu übersetzen.
Dies ist die beste Lösung, die ich beim Umgang mit Typescript-Klassen und JSON-Objekten gefunden habe.
quelle
Es gibt noch nichts, was automatisch überprüft werden könnte, ob das vom Server empfangene JSON-Objekt die erwarteten (read entspricht den) Schnittstelleneigenschaften des Typoskripts aufweist. Sie können jedoch benutzerdefinierte Typschutzvorrichtungen verwenden
Betrachtet man die folgende Schnittstelle und ein dummes JSON-Objekt (es könnte jeder Typ sein):
Drei mögliche Wege:
A. Typ Assertion oder einfache statische Umwandlung nach der Variablen
B. Einfacher statischer Guss vor der Variablen und zwischen Diamanten
C. Erweiterte dynamische Umwandlung, Sie überprüfen selbst die Struktur des Objekts
Sie können hier mit diesem Beispiel spielen
Beachten Sie, dass die Schwierigkeit hier darin besteht, die
isMyInterface
Funktion zu schreiben . Ich hoffe, TS wird früher oder später einen Dekorator hinzufügen, um komplexe Eingaben in die Laufzeit zu exportieren und die Laufzeit die Objektstruktur bei Bedarf überprüfen zu lassen. Im Moment können Sie entweder einen JSON-Schema-Validator verwenden, dessen Zweck ungefähr der gleiche ist, ODER diesen Generator für die Überprüfung des Laufzeit-Typsquelle
In meinem Fall funktioniert es. Ich habe Funktionen Object.assign (Ziel, Quellen ...) verwendet . Zuerst wird das richtige Objekt erstellt und dann werden die Daten vom JSON-Objekt auf das Ziel kopiert. Beispiel:
Und ein fortgeschritteneres Anwendungsbeispiel. Ein Beispiel mit dem Array.
quelle
this.users[i] = new User(); Object.assign(this.users[i], users[i])
this.users[i] = Object.assign(new User(), users[i]);
Während es nicht per se gießt; Ich habe festgestellt, dass https://github.com/JohnWhiteTB/TypedJSON eine nützliche Alternative ist.
quelle
Sie können ein Objekt
interface
Ihres Typs (SomeType
) erstellen und das Objekt darin umwandeln.quelle
Wenn Sie Ihr json-Objekt in eine Typoskriptklasse umwandeln müssen und die Instanzmethoden im resultierenden Objekt verfügbar sind, müssen Sie es verwenden
Object.setPrototypeOf
, wie ich es im folgenden Code-Snippet getan habe:quelle
Eine alte Frage mit meist richtigen, aber nicht sehr effizienten Antworten. Das was ich vorschlage:
Erstellen Sie eine Basisklasse, die die Methode init () und statische Umwandlungsmethoden enthält (für ein einzelnes Objekt und ein Array). Die statischen Methoden können überall sein; Die Version mit der Basisklasse und init () ermöglicht anschließend einfache Erweiterungen.
Ähnliche Mechaniken (mit assign () ) wurden in @ Adam111p post erwähnt. Nur eine andere (vollständigere) Möglichkeit, dies zu tun. @ Timothy Perez kritisiert zuweisen () , aber imho ist es hier völlig angemessen.
Implementieren Sie eine abgeleitete (die reale) Klasse:
Jetzt können wir ein aus dem Dienst abgerufenes Objekt umwandeln:
Alle Hierarchien von SubjectArea Objekten haben die richtige Klasse.
Ein Anwendungsfall / Beispiel; Erstellen Sie einen Angular-Service (wieder abstrakte Basisklasse):
Die Verwendung wird sehr einfach; Erstellen Sie einen Area-Service:
Die Methode get () des Dienstes gibt ein Versprechen eines Arrays zurück, das bereits als SubjectArea umgewandelt wurde Objekte umgewandelt wurde (gesamte Hierarchie).
Sagen wir jetzt, wir haben eine andere Klasse:
Das Erstellen eines Dienstes, der Daten abruft und in die richtige Klasse umwandelt, ist so einfach wie:
quelle
Verwenden Sie eine von einer Schnittstelle erweiterte Klasse.
Dann:
Und das Beste:
ToWhat wird ein Controller von DataInterface.
quelle
https://jvilk.com/MakeTypes/
Sie können diese Site verwenden, um einen Proxy für Sie zu generieren. Es generiert eine Klasse und kann Ihr Eingabe-JSON-Objekt analysieren und validieren.
quelle
In den letzten TS können Sie Folgendes tun:
Und als Benutzer wie folgt:
quelle
Ich hatte ein ähnliches Bedürfnis. Ich wollte etwas, das mir eine einfache Transformation von / zu JSON ermöglicht, die von einem REST-API-Aufruf zu / von einer bestimmten Klassendefinition stammt. Die Lösungen, die ich gefunden habe, waren unzureichend oder dazu gedacht, den Code meiner Klassen neu zu schreiben und Anmerkungen oder Ähnliches hinzuzufügen.
Ich wollte so etwas wie GSON wird in Java verwendet, um Klassen zu / von JSON-Objekten zu serialisieren / deserialisieren.
In Kombination mit der späteren Notwendigkeit, dass der Konverter auch in JS funktioniert, beendete ich das Schreiben meines eigenen Pakets.
Es hat jedoch ein wenig Overhead. Aber wenn es gestartet wird, ist es sehr praktisch beim Hinzufügen und Bearbeiten.
Sie initialisieren das Modul mit:
Dann verwenden Sie in Ihrem Code das initialisierte Modul wie folgt:
oder an JSON:
Verwenden Sie diesen Link zum npm-Paket und eine ausführliche Erklärung zur Arbeit mit dem Modul: json-class-converter
Wickelte es auch für die
Verwendung in Angular ein in: Angular -JSON-Class-Converter
quelle
Übergeben Sie das Objekt unverändert an den Klassenkonstruktor. Keine Konventionen oder Prüfungen
quelle
Sie können dieses npm-Paket verwenden. https://www.npmjs.com/package/class-converter
Es ist einfach zu bedienen, zum Beispiel:
quelle
Persönlich finde ich es entsetzlich, dass Typoskript keine Endpunktdefinition zulässt, um den Typ des empfangenen Objekts anzugeben. Da dies tatsächlich der Fall zu sein scheint, würde ich das tun, was ich mit anderen Sprachen getan habe, und das heißt, ich würde das JSON-Objekt von der Klassendefinition trennen und die Klassendefinition das JSON-Objekt als einziges Datenelement verwenden lassen .
Ich verachte Boilerplate-Code, daher ist es für mich normalerweise eine Frage des Erreichens des gewünschten Ergebnisses mit der geringsten Menge an Code unter Beibehaltung des Typs.
Betrachten Sie die folgenden JSON-Objektstrukturdefinitionen - diese würden Sie an einem Endpunkt erhalten, es handelt sich nur um Strukturdefinitionen, keine Methoden.
Wenn wir das Obige objektorientiert betrachten, sind die obigen Schnittstellen keine Klassen, da sie nur eine Datenstruktur definieren. Eine Klasse in OO-Begriffen definiert Daten und den Code, der sie verarbeitet.
Also definieren wir jetzt eine Klasse, die Daten und den Code angibt, der sie verarbeitet ...
Und jetzt können wir einfach jedes Objekt übergeben, das der IPerson-Struktur entspricht, und uns auf den Weg machen ...
Auf die gleiche Weise können wir jetzt das an Ihrem Endpunkt empfangene Objekt mit etwas in der Art von ...
Dies ist viel leistungsfähiger und beansprucht die Hälfte des Speichers zum Kopieren der Daten, während die Menge an Boilerplate-Code, die Sie für jeden Entitätstyp schreiben müssen, erheblich reduziert wird. Es basiert einfach auf der von TypeScript bereitgestellten Typensicherheit.
quelle
Verwenden Sie die Erklärung 'as':
quelle
MyClass
.Dies ist eine einfache und wirklich gute Option
Und dann wirst du haben
quelle
Ich habe diese Bibliothek hier verwendet: https://github.com/pleerock/class-transformer
Implementierung:
Manchmal müssen Sie die JSON-Werte für plainToClass analysieren, um zu verstehen, dass es sich um JSON-formatierte Daten handelt
quelle
Ich verwende Angular 6 im Frontend und Spring Boot-Anwendung im Backend, die Java-Objekte zurückgibt. Alles, was ich tun muss, ist, eine ähnliche Klasse in der Winkelanwendung zu definieren, die übereinstimmende Eigenschaften hat, und dann kann ich das Objekt als Winkelklassenobjekt akzeptieren ( comp als Firma) im folgenden Beispiel ).
Lesen Sie zum Beispiel den folgenden Front-End-Code. Lassen Sie mich in Kommentaren wissen, ob etwas mehr Klarheit benötigt.
Dabei ist Unternehmen ein Entitätsobjekt in der Spring Boot App und auch eine Klasse in Angular.
quelle