Bagaimana cara melemparkan objek JSON ke kelas naskah

393

Saya membaca objek JSON dari server REST jauh. Objek JSON ini memiliki semua properti dari kelas naskah (menurut desain). Bagaimana cara melemparkan objek JSON yang diterima ke tipe var?

Saya tidak ingin mengisi var naskah (yaitu memiliki konstruktor yang mengambil objek JSON ini). Ini besar dan menyalin segala sesuatu di seluruh sub-objek dengan sub-objek & properti dengan properti akan membutuhkan banyak waktu.

Pembaruan: Namun Anda dapat melemparkannya ke antarmuka naskah!

David Thielen
sumber
Anda dapat menggunakan github.com/vojtechhabarta/typescript-generator untuk menghasilkan antarmuka TypeScript jika JSON Anda dipetakan menggunakan kelas Java
Vojta
Saya telah dikodekan perpustakaan kecil pengecoran: sulphur-blog.azurewebsites.net/typescript-mini-cast-library
Camille Wintz
1
Objek JSON = objek Notasi Objek JavaScript. Tidak memiliki cukup objek di sana, saya katakan kita melemparkan pasangan lagi untuk ukuran yang baik.
bug-a-lot
1
Saya telah membuat alat untuk beshanoe.github.io/json2ts
beshanoe
Membuat prototipe kelas TypeScript untuk mendefinisikan objek Anda tidak akan merusak kode produksi nyata. Lihatlah file JS yang dikompilasi, semua definisi akan dihapus, karena mereka bukan bagian dari JS.
FisNaN

Jawaban:

167

Anda tidak dapat dengan mudah memasukkan hasil JavaScript lama-polos dari permintaan Ajax ke instance kelas JavaScript / TypeScript. Ada sejumlah teknik untuk melakukannya, dan umumnya melibatkan menyalin data. Kecuali Anda membuat instance kelas, itu tidak akan memiliki metode atau properti. Ini akan tetap menjadi objek JavaScript sederhana.

Sementara jika Anda hanya berurusan dengan data, Anda bisa melakukan cast ke antarmuka (karena ini murni struktur waktu kompilasi), ini akan mengharuskan Anda menggunakan kelas TypeScript yang menggunakan instance data dan melakukan operasi dengan data itu.

Beberapa contoh menyalin data:

  1. Menyalin objek AJAX JSON ke Objek yang ada
  2. Parsing String JSON menjadi Prototipe Objek Tertentu dalam JavaScript

Intinya, Anda baru saja:

var d = new MyRichObject();
d.copyInto(jsonResult);
WiredPrairie
sumber
Saya setuju dengan jawaban Anda. Sebagai tambahan, meskipun saya tidak berada di tempat untuk mencarinya dan mengujinya sekarang, saya pikir kedua langkah itu dapat dikombinasikan dengan memberikan fungsi bangun sebagai param JSON.parse(). Keduanya masih perlu dilakukan, tetapi secara sintaksis keduanya dapat digabungkan.
JAAulde
Tentu, itu mungkin berhasil juga - saya tidak memiliki perasaan apakah itu akan lebih efisien meskipun karena perlu memanggil fungsi panggilan tambahan untuk setiap properti.
WiredPrairie
Jelas bukan jawaban yang saya cari :( Karena penasaran mengapa ini? Menurut saya cara javascript berfungsi bahwa ini seharusnya bisa dilakukan.
David Thielen
Tidak, ini tidak berfungsi di TypeScript karena tidak ada cara sederhana dalam JavaScript untuk melakukan ini.
WiredPrairie
1
Bagaimana denganObject.setPrototypeOf
Petah
102

Saya memiliki masalah yang sama dan saya telah menemukan perpustakaan yang melakukan pekerjaan: https://github.com/pleerock/class-transformer .

Ini berfungsi seperti ini:

let jsonObject = response.json() as Object;
let fooInstance = plainToClass(Models.Foo, jsonObject);
return fooInstance;

Ini mendukung anak-anak yang bersarang tetapi Anda harus mendekorasi anggota kelas Anda.

Pak
sumber
14
Perpustakaan kecil yang brilian ini menyelesaikannya dengan sempurna dengan sedikit usaha (jangan lupa @Typepenjelasan Anda ). Jawaban ini layak mendapat kredit lebih banyak.
Benny Bottema
Oh wow !, perpustakaan ini tidak begitu kecil, mungkin saja semua yang Anda butuhkan, bahkan memungkinkan Anda mengontrol transformasi dengan @transformator dekorator: D
Diego Fernando Murillo Valenci
3
Perhatikan bahwa perpustakaan ini hampir tidak dipelihara lagi. Itu tidak berfungsi dengan Angular5 + lagi dan karena mereka bahkan tidak menggabungkan permintaan tarik lagi, saya tidak berpikir mereka akan bekerja pada itu dalam waktu dekat. Ini perpustakaan yang bagus.
kentor
Ada solusi untuk Angular5 + (ini sebenarnya adalah Angular Bug): github.com/typestack/class-transformer/issues/108
Pak
2
Ini berfungsi dengan baik di Angular 6 (setidaknya untuk kasus penggunaan saya yang hanya untuk benar-benar memetakan JSON <=> Kelas)
tftd
54

Dalam TypeScript Anda dapat melakukan pernyataan tipe menggunakan antarmuka dan generik seperti:

var json = Utilities.JSONLoader.loadFromFile("../docs/location_map.json");
var locations: Array<ILocationMap> = JSON.parse(json).location;

Di mana ILocationMap menjelaskan bentuk data Anda. Keuntungan dari metode ini adalah bahwa JSON Anda bisa mengandung lebih banyak properti tetapi bentuknya memenuhi kondisi antarmuka.

Saya harap itu membantu!

pengguna756310
sumber
49
FYI: Ini adalah tipe pernyataan, bukan gips.
WiredPrairie
6
Lihat di sini untuk perbedaan antara pernyataan jenis dan pemain .
Stefan Hanke
7
Di mana saya dapat menemukan Utilities.JSONLoader?
HypeXR
22
Tapi itu tidak akan memiliki metode apa pun, seperti yang disebutkan dalam jawaban.
Martín Coll
1
@StefanHanke sepertinya URL sedikit berubah: "Ketik Ketegasan vs. Casting"
ruffin
37

Jika Anda menggunakan ES6, coba ini:

class Client{
  name: string

  displayName(){
    console.log(this.name)
  }
}

service.getClientFromAPI().then(clientData => {

  // Here the client data from API only have the "name" field
  // If we want to use the Client class methods on this data object we need to:
  let clientWithType = Object.assign(new Client(), clientData)

  clientWithType.displayName()
})

Tetapi cara ini tidak akan bekerja pada objek sarang , sedihnya.

migcoder
sumber
4
Mereka memintanya dalam naskah.
joe.feser
HI @ joe.feser, saya menyebutkan ES6 karena dengan cara ini metode 'Object.assign' diperlukan.
migcoder
1
Jika konstruktor default tidak ada, instance target dapat dibuat Object.create(MyClass.prototype), melewati konstruktor sama sekali.
Marcello
Penjelasan lebih lanjut tentang batasan objek bersarang lihat di stackoverflow.com/questions/22885995/…
Michael Freidgeim
28

Saya menemukan artikel yang sangat menarik tentang pengecoran generik JSON ke Kelas Script:

http://cloudmark.github.io/Json-Mapping/

Anda berakhir dengan kode berikut:

let example = {
                "name": "Mark", 
                "surname": "Galea", 
                "age": 30, 
                "address": {
                  "first-line": "Some where", 
                  "second-line": "Over Here",
                  "city": "In This City"
                }
              };

MapUtils.deserialize(Person, example);  // custom class
Philip
sumber
20

TLDR: Satu liner

// This assumes your constructor method will assign properties from the arg.
.map((instanceData: MyClass) => new MyClass(instanceData));

Jawaban Terperinci

Saya tidak akan merekomendasikan pendekatan Object.assign, karena dapat secara tidak tepat mengotori instance kelas Anda dengan properti yang tidak relevan (serta penutupan yang ditentukan) yang tidak dideklarasikan di dalam kelas itu sendiri.

Di kelas Anda mencoba deserialize ke, saya akan memastikan properti apa pun yang Anda inginkan deserialized didefinisikan (null, array kosong, dll). Dengan mendefinisikan properti Anda dengan nilai awal, Anda mengekspos visibilitas mereka ketika mencoba untuk mengulangi anggota kelas untuk memberikan nilai (lihat metode deserialize di bawah).

export class Person {
  public name: string = null;
  public favoriteSites: string[] = [];

  private age: number = null;
  private id: number = null;
  private active: boolean;

  constructor(instanceData?: Person) {
    if (instanceData) {
      this.deserialize(instanceData);
    }
  }

  private deserialize(instanceData: Person) {
    // Note this.active will not be listed in keys since it's declared, but not defined
    const keys = Object.keys(this);

    for (const key of keys) {
      if (instanceData.hasOwnProperty(key)) {
        this[key] = instanceData[key];
      }
    }
  }
}

Pada contoh di atas, saya cukup membuat metode deserialize. Dalam contoh dunia nyata, saya akan membuatnya terpusat di kelas dasar yang dapat digunakan kembali atau metode layanan.

Berikut adalah cara memanfaatkan ini dalam sesuatu seperti resp http ...

this.http.get(ENDPOINT_URL)
  .map(res => res.json())
  .map((resp: Person) => new Person(resp) ) );

Jika tslint / ide mengeluh tentang tipe argumen yang tidak kompatibel, cukup masukkan argumen ke tipe yang sama menggunakan kurung sudut <YourClassName>, contoh:

const person = new Person(<Person> { name: 'John', age: 35, id: 1 });

Jika Anda memiliki anggota kelas yang memiliki tipe tertentu (alias: instance dari kelas lain), maka Anda dapat meminta mereka memasukkannya ke dalam instance yang diketik melalui metode pengambil / penyetel.

export class Person {
  private _acct: UserAcct = null;
  private _tasks: Task[] = [];

  // ctor & deserialize methods...

  public get acct(): UserAcct {
    return this.acct;
  }
  public set acct(acctData: UserAcct) {
    this._acct = new UserAcct(acctData);
  }

  public get tasks(): Task[] {
    return this._tasks;
  }

  public set tasks(taskData: Task[]) {
    this._tasks = taskData.map(task => new Task(task));
  }
}

Contoh di atas akan menghapus daftar sertifikat dan daftar tugas ke dalam instance kelas masing-masing.

Timothy Perez
sumber
Saya mendapatkan pesan kesalahan ini: Ketik '{name: string, age: number, id: number}' tidak dapat dikonversi untuk mengetikkan 'Person'. Properti 'id' bersifat pribadi dalam tipe 'Orang' tetapi tidak dalam tipe '{nama: string, usia: angka, id: angka}'
utiq
Bagaimana saya harus menggunakan ini dengan enum? Apakah saya harus menggunakan pendekatan tipe khusus dan menambahkan pengambil dan penyetel untuk itu?
Tadija Bagarić
@TimothyParez Kapan Anda mengatur tugas?
Kay
Saya mencoba melakukan sesuatu yang serupa tetapi tugas array saya kosong ketika saya console.log orang.
Kay
Untuk mengkompilasi ini, saya harus menambahkan Indeks Tanda Tangan ke kelas: kelas ekspor Orang {[key: string]: any (...)}
Asimov
18

Dengan asumsi json memiliki properti yang sama dengan kelas naskah Anda, Anda tidak perlu menyalin properti Json Anda ke objek naskah Anda. Anda hanya perlu membangun objek skrip Anda melewati data json di konstruktor.

Dalam panggilan balik ajax Anda, Anda menerima perusahaan:

onReceiveCompany( jsonCompany : any ) 
{
   let newCompany = new Company( jsonCompany );

   // call the methods on your newCompany object ...
}

Untuk membuatnya bekerja:

1) Tambahkan konstruktor di kelas naskah Anda yang menggunakan data json sebagai parameter. Dalam konstruktor yang Anda memperpanjang objek json Anda dengan jQuery, seperti ini: $.extend( this, jsonData). $ .extend memungkinkan menjaga prototipe javascript sambil menambahkan properti objek json.

2) Catatan Anda harus melakukan hal yang sama untuk objek yang ditautkan. Dalam kasus Karyawan dalam contoh, Anda juga membuat konstruktor yang mengambil bagian dari data json untuk karyawan. Anda memanggil $ .map untuk menerjemahkan karyawan json ke objek naskah skrip Karyawan.

export class Company
{
    Employees : Employee[];

    constructor( jsonData: any )
    {
        $.extend( this, jsonData);

        if ( jsonData.Employees )
            this.Employees = $.map( jsonData.Employees , (emp) => {
                return new Employee ( emp );  });
    }
}

export class Employee
{
    name: string;
    salary: number;

    constructor( jsonData: any )
    {
        $.extend( this, jsonData);
    }
}

Ini adalah solusi terbaik yang saya temukan ketika berhadapan dengan kelas-kelas TypeScript dan objek json.

Anthony Brenelière
sumber
Saya lebih suka solusi ini daripada mengimplementasikan dan memelihara antarmuka, karena aplikasi Angular2 saya memiliki model aplikasi nyata yang mungkin berbeda dengan model layanan web yang dikonsumsi aplikasi saya. Ini dapat memiliki data pribadi dan properti yang dihitung.
Anthony Brenelière
7
Menggunakan JQuery dalam proyek Angular adalah ide yang buruk. Dan jika model Anda mengandung banyak fungsi, mereka bukan model lagi.
Davor
1
@Davor Maksud Anda POJO, atau model? POJO (pada dasarnya objek polos) tidak memiliki fungsi, sedangkan model adalah istilah yang lebih luas, dan itu termasuk repositori. Pola repositori, berbeda dengan POJO, adalah tentang fungsi, tetapi masih model.
forsberg
@ Nikmat: menggunakan JQuery di proyek Angular bukan ide yang buruk asalkan Anda tidak menggunakannya untuk memanipulasi DOM, yang memang merupakan ide yang mengerikan. Saya memang menggunakan perpustakaan apa pun yang saya butuhkan untuk proyek Angular saya, dan untuk jQuery itu bukan pilihan karena proyek saya menggunakan SignalR yang bergantung padanya. Dalam kasus kelas, sekarang digunakan oleh ES6 javascript, data diakses dengan properti yang berfungsi yang merangkum cara data disimpan dalam memori. Untuk konstruktor, ada cara yang tepat menggunakan pabrik.
Anthony Brenelière
OP jelas tentang model data biasa untuk REST. Anda membuatnya menjadi rumit, kawan. Dan ya, Anda bisa menggunakan Jquery untuk hal-hal tambahan, tetapi Anda mengimpor perpustakaan besar untuk menggunakan 1% dari itu. Itu adalah bau kode jika saya pernah melihatnya.
Davor
18

Tidak ada yang belum secara otomatis memeriksa apakah objek JSON yang Anda terima dari server memiliki properti antarmuka typescript yang diharapkan (baca sesuai dengan). Tapi Anda bisa menggunakannya Penjaga Tipe Buatan Pengguna

Mempertimbangkan antarmuka berikut dan objek json konyol (bisa jenis apa saja):

interface MyInterface {
    key: string;
 }

const json: object = { "key": "value" }

Tiga cara yang mungkin:

A. Ketikkan Penegasan atau pemeran statis sederhana yang ditempatkan setelah variabel

const myObject: MyInterface = json as MyInterface;

B. Pemain statis sederhana, sebelum variabel dan antara berlian

const myObject: MyInterface = <MyInterface>json;

C. Pemain dinamis canggih, Anda memeriksa sendiri struktur objek

function isMyInterface(json: any): json is MyInterface {
    // silly condition to consider json as conform for MyInterface
    return typeof json.key === "string";
}

if (isMyInterface(json)) {
    console.log(json.key)
}
else {
        throw new Error(`Expected MyInterface, got '${json}'.`);
}

Anda dapat bermain dengan contoh ini di sini

Perhatikan bahwa kesulitannya adalah menulis isMyInterfacefungsi. Saya berharap TS akan menambahkan dekorator cepat atau lambat untuk mengekspor pengetikan kompleks ke runtime dan membiarkan runtime memeriksa struktur objek saat diperlukan. Untuk saat ini, Anda bisa menggunakan validator skema json yang tujuannya kira-kira sama ATAU generator fungsi pemeriksaan tipe runtime ini

Flavien Volken
sumber
1
Jawaban Anda harus di atas saya kira
afzalex
Pastinya. Ini adalah jawaban terbaik yang bergantung langsung pada situs web ts.
Burak Karakuş
15

Dalam kasus saya ini berfungsi. Saya menggunakan fungsi Object.assign (target, sumber ...) . Pertama, pembuatan objek yang benar, kemudian menyalin data dari objek json ke target. Contoh:

let u:User = new User();
Object.assign(u , jsonUsers);

Dan contoh penggunaan yang lebih maju. Contoh menggunakan array.

this.someService.getUsers().then((users: User[]) => {
  this.users = [];
  for (let i in users) {
    let u:User = new User();
    Object.assign(u , users[i]);
    this.users[i] = u;
    console.log("user:" + this.users[i].id);
    console.log("user id from function(test it work) :" + this.users[i].getId());
  }

});

export class User {
  id:number;
  name:string;
  fullname:string;
  email:string;

  public getId(){
    return this.id;
  }
}
Adam111p
sumber
Apa yang terjadi ketika Anda memiliki properti pribadi?
prasanthv
Karena objek jsonUser bukan kelas pengguna. Tanpa operasi Object.assign (u, jsonUsers); Anda tidak dapat menggunakan fungsi getId (). Hanya setelah menetapkan Anda mendapatkan objek Pengguna yang valid di mana Anda dapat menggunakan fungsi getId (). Fungsi getId () hanya untuk contoh bahwa operasi berhasil.
Adam111p
Anda dapat melewati temp var - just dothis.users[i] = new User(); Object.assign(this.users[i], users[i])
cyptus
atau bahkan lebih baik menggunakan nilai pengembalian:this.users[i] = Object.assign(new User(), users[i]);
cyptus
Versi panjang ini hanya untuk penjelasan. Anda dapat mempersingkat kode sebanyak yang Anda suka :)
Adam111p
6

Meskipun tidak casting per se; Saya telah menemukan https://github.com/JohnWhiteTB/TypedJSON sebagai alternatif yang bermanfaat.

@JsonObject
class Person {
    @JsonMember
    firstName: string;

    @JsonMember
    lastName: string;

    public getFullname() {
        return this.firstName + " " + this.lastName;
    }
}
var person = TypedJSON.parse('{ "firstName": "John", "lastName": "Doe" }', Person);

person instanceof Person; // true
person.getFullname(); // "John Doe"
Neil
sumber
1
Itu tidak casting, apa yang sebenarnya dilakukannya?
DanielM
1
Solusi ini membutuhkan banyak anotasi. Apakah benar-benar tidak ada cara yang lebih mudah?
JPNotADragon
3

Anda bisa membuat interfacetipe Anda ( SomeType) dan melemparkan objek ke dalamnya.

const typedObject: SomeType = <SomeType> responseObject;
Jayant Varshney
sumber
3

Jika Anda perlu melemparkan objek json Anda ke kelas naskah dan memiliki metode instance yang tersedia di objek yang dihasilkan yang perlu Anda gunakan Object.setPrototypeOf, seperti yang saya lakukan dalam potongan kode di bawah:

Object.setPrototypeOf(jsonObject, YourTypescriptClass.prototype)
s_bighead
sumber
2

Pertanyaan lama dengan sebagian besar jawaban yang benar, tetapi tidak terlalu efisien. Inilah yang saya usulkan:

Buat kelas dasar yang berisi metode init () dan metode cast statis (untuk objek tunggal dan array). Metode statis bisa di mana saja; versi dengan kelas dasar dan init () memungkinkan ekstensi yang mudah sesudahnya.

export class ContentItem {
    // parameters: doc - plain JS object, proto - class we want to cast to (subclass of ContentItem)
    static castAs<T extends ContentItem>(doc: T, proto: typeof ContentItem): T {
        // if we already have the correct class skip the cast
        if (doc instanceof proto) { return doc; }
        // create a new object (create), and copy over all properties (assign)
        const d: T = Object.create(proto.prototype);
        Object.assign(d, doc);
        // reason to extend the base class - we want to be able to call init() after cast
        d.init(); 
        return d;
    }
    // another method casts an array
    static castAllAs<T extends ContentItem>(docs: T[], proto: typeof ContentItem): T[] {
        return docs.map(d => ContentItem.castAs(d, proto));
    }
    init() { }
}

Mekanika serupa (dengan assign () ) telah disebutkan dalam pos @ Adam111p. Hanya cara lain (lebih lengkap) untuk melakukannya. @Timothy Perez kritis terhadap assign () , tetapi jika itu sepenuhnya sesuai di sini.

Menerapkan kelas turunan (nyata):

import { ContentItem } from './content-item';

export class SubjectArea extends ContentItem {
    id: number;
    title: string;
    areas: SubjectArea[]; // contains embedded objects
    depth: number;

    // method will be unavailable unless we use cast
    lead(): string {
        return '. '.repeat(this.depth);
    }

    // in case we have embedded objects, call cast on them here
    init() {
        if (this.areas) {
            this.areas = ContentItem.castAllAs(this.areas, SubjectArea);
        }
    }
}

Sekarang kita bisa melemparkan objek yang diambil dari layanan:

const area = ContentItem.castAs<SubjectArea>(docFromREST, SubjectArea);

Semua hierarki objek SubjectArea akan memiliki kelas yang benar.

Sebuah use case / example; buat layanan Angular (kelas dasar abstrak lagi):

export abstract class BaseService<T extends ContentItem> {
  BASE_URL = 'http://host:port/';
  protected abstract http: Http;
  abstract path: string;
  abstract subClass: typeof ContentItem;

  cast(source: T): T {
    return ContentItem.castAs(source, this.subClass);
  }
  castAll(source: T[]): T[] {
    return ContentItem.castAllAs(source, this.subClass);
  }

  constructor() { }

  get(): Promise<T[]> {
    const value = this.http.get(`${this.BASE_URL}${this.path}`)
      .toPromise()
      .then(response => {
        const items: T[] = this.castAll(response.json());
        return items;
      });
    return value;
  }
}

Penggunaannya menjadi sangat sederhana; buat layanan Area:

@Injectable()
export class SubjectAreaService extends BaseService<SubjectArea> {
  path = 'area';
  subClass = SubjectArea;

  constructor(protected http: Http) { super(); }
}

get () metode layanan akan mengembalikan Janji array yang sudah dilemparkan sebagai objek SubjectArea (seluruh hierarki)

Sekarang katakanlah, kita memiliki kelas lain:

export class OtherItem extends ContentItem {...}

Membuat layanan yang mengambil data dan melakukan cast ke kelas yang benar adalah sesederhana:

@Injectable()
export class OtherItemService extends BaseService<OtherItem> {
  path = 'other';
  subClass = OtherItem;

  constructor(protected http: Http) { super(); }
}
Normunds Kalnberzins
sumber
2

Gunakan kelas yang diperluas dari antarmuka.

Kemudian:

Object.assign(
                new ToWhat(),
                what
              )

Dan terbaik:

Object.assign(
                    new ToWhat(),
                    <IDataInterface>what
                  )

ToWhat menjadi pengontrol DataInterface.

Sam
sumber
1

https://jvilk.com/MakeTypes/

Anda dapat menggunakan situs ini untuk menghasilkan proxy untuk Anda. ini menghasilkan kelas dan dapat mengurai dan memvalidasi objek JSON input Anda.

Amir Mehrabi
sumber
0

Dalam lates TS Anda dapat melakukan hal ini:

const isMyInterface = (val: any): val is MyInterface => {
  if (!val) { return false; }
  if (!val.myProp) { return false; }
  return true;
};

Dan daripada pengguna seperti ini:

if (isMyInterface(data)) {
 // now data will be type of MyInterface
}
Jaroslav
sumber
0

Saya bertemu dengan kebutuhan yang sama. Saya menginginkan sesuatu yang akan memberi saya transformasi mudah dari / ke JSON yang berasal dari panggilan api REST ke / dari definisi kelas tertentu. Solusi yang saya temukan tidak cukup atau dimaksudkan untuk menulis ulang kode kelas saya dan menambahkan anotasi atau similars.

Saya ingin sesuatu seperti GSON digunakan di Jawa untuk membuat serial / deserialize kelas ke / dari objek JSON.

Dikombinasikan dengan kebutuhan nanti, bahwa konverter akan berfungsi di JS juga, saya akhirnya menulis paket saya sendiri.

Meskipun demikian, sedikit overhead. Tetapi ketika mulai sangat nyaman dalam menambah dan mengedit.

Anda menginisialisasi modul dengan:

  1. skema konversi - memungkinkan untuk memetakan antar bidang dan menentukan bagaimana konversi akan dilakukan
  2. Array peta kelas
  3. Peta fungsi konversi - untuk konversi khusus.

Kemudian dalam kode Anda, Anda menggunakan modul yang diinisialisasi seperti:

const convertedNewClassesArray : MyClass[] = this.converter.convert<MyClass>(jsonObjArray, 'MyClass');

const convertedNewClass : MyClass = this.converter.convertOneObject<MyClass>(jsonObj, 'MyClass');

atau, ke JSON:

const jsonObject = this.converter.convertToJson(myClassInstance);

Gunakan tautan ini ke paket npm dan juga penjelasan terperinci tentang cara bekerja dengan modul: json-class-converter

Juga dibungkus untuk
penggunaan sudut dalam: angular-json-class-converter

Doronm
sumber
0

Berikan objek apa adanya ke konstruktor kelas; Tidak ada konvensi atau pemeriksaan

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

class Person {
   constructor(private person: iPerson) { }

   toString(): string {
      return this.person.name + ' is ' + this.person.age;
   }  
}


// runs this as // 
const object1 = { name: 'Watson1', age: 64 };
const object2 = { name: 'Watson2' };            // age is missing

const person1 = new Person(object1);
const person2 = new Person(object2 as iPerson); // now matches constructor

console.log(person1.toString())  // Watson1 is 64
console.log(person2.toString())  // Watson2 is undefined
Lars Klingsten
sumber
0

Anda dapat menggunakan paket npm ini. https://www.npmjs.com/package/class-converter

Mudah digunakan, misalnya:

class UserModel {
  @property('i')
  id: number;

  @property('n')
  name: string;
}

const userRaw = {
  i: 1234,
  n: 'name',
};

// use toClass to convert plain object to class
const userModel = toClass(userRaw, UserModel);
// you will get a class, just like below one
// const userModel = {
//   id: 1234,
//   name: 'name',
// }
QC-cheetah
sumber
0

Secara pribadi saya menemukan itu mengerikan bahwa naskah tidak mengizinkan definisi titik akhir untuk menentukan jenis objek yang diterima. Tampaknya memang demikian, saya akan melakukan apa yang telah saya lakukan dengan bahasa lain, dan itu adalah bahwa saya akan memisahkan objek JSON dari definisi kelas, dan meminta definisi kelas menggunakan objek JSON sebagai satu-satunya anggota data .

Saya membenci kode boilerplate, jadi bagi saya biasanya masalah mendapatkan hasil yang diinginkan dengan jumlah kode paling sedikit sambil mempertahankan tipe.

Pertimbangkan definisi struktur objek JSON berikut - ini adalah apa yang akan Anda terima pada titik akhir, mereka hanya definisi struktur, tidak ada metode.

interface IAddress {
    street: string;
    city: string;
    state: string;
    zip: string;
}

interface IPerson {
    name: string;
    address: IAddress;
}

Jika kita memikirkan hal-hal di atas dalam istilah berorientasi objek, antarmuka di atas bukan kelas karena mereka hanya mendefinisikan struktur data. Kelas dalam istilah OO mendefinisikan data dan kode yang beroperasi di atasnya.

Jadi sekarang kita mendefinisikan kelas yang menentukan data dan kode yang beroperasi di dalamnya ...

class Person {
    person: IPerson;

    constructor(person: IPerson) {
        this.person = person;
    }

    // accessors
    getName(): string {
        return person.name;
    }

    getAddress(): IAddress {
        return person.address;
    }

    // You could write a generic getter for any value in person, 
    // no matter how deep, by accepting a variable number of string params

    // methods
    distanceFrom(address: IAddress): float {
        // Calculate distance from the passed address to this persons IAddress
        return 0.0;
    }
}

Dan sekarang kita bisa dengan mudah melewati objek apa pun yang sesuai dengan struktur IPerson dan berada di jalan kita ...

   Person person = new Person({
            name: "persons name",
            address: {
                street: "A street address",
                city: "a city",
                state: "a state",
                zip: "A zipcode"
            }
        });

Dengan cara yang sama kita sekarang dapat memproses objek yang diterima di titik akhir Anda dengan sesuatu di sepanjang ...

Person person = new Person(req.body);    // As in an object received via a POST call

person.distanceFrom({ street: "Some street address", etc.});

Ini jauh lebih berkinerja dan menggunakan setengah memori menyalin data, sementara secara signifikan mengurangi jumlah kode boilerplate Anda harus menulis untuk setiap jenis entitas. Itu hanya bergantung pada keamanan jenis yang disediakan oleh TypeScript.

Rodney P. Barbati
sumber
0

Gunakan deklarasi 'sebagai':

const data = JSON.parse(response.data) as MyClass;
Daniel Valdebenito
sumber
Teknik ini disebutkan dalam jawaban ini dari dua tahun sebelumnya , dan seperti yang telah dibahas di tempat lain, tidak menambahkan fungsi yang dapat dideklarasikan MyClass.
Monyet sesat
-1

Ini adalah pilihan yang sederhana dan sangat bagus

let person = "{"name":"Sam","Age":"30"}";

const jsonParse: ((key: string, value: any) => any) | undefined = undefined;
let objectConverted = JSON.parse(textValue, jsonParse);

Dan kemudian Anda akan memilikinya

objectConverted.name
SamazoOo
sumber
-1

Saya menggunakan perpustakaan ini di sini: https://github.com/pleerock/class-transformer

<script lang="ts">
    import { plainToClass } from 'class-transformer';
</script>

Penerapan:

private async getClassTypeValue() {
  const value = await plainToClass(ProductNewsItem, JSON.parse(response.data));
}

Terkadang Anda harus menguraikan nilai JSON untuk plainToClass untuk memahami bahwa itu adalah data yang diformat JSON

Mac Chibueze
sumber
Pustaka 'kelas-transformator' sudah disarankan dalam jawaban lain di atas stackoverflow.com/a/40042282/52277
Michael Freidgeim
-1

Saya menggunakan Angular 6 di aplikasi frontend dan Spring Boot di backend yang mengembalikan Java Objects. Yang perlu saya lakukan adalah mendefinisikan kelas yang sama pada aplikasi sudut yang memiliki properti yang cocok dan kemudian saya dapat menerima objek 'sebagai' objek kelas sudut ( comp sebagai Perusahaan dalam contoh di bawah).

Lihat kode ujung depan di bawah misalnya. Beri tahu saya di komentar jika ada yang perlu lebih jelas.

  createCompany() {
    let company = new Company();
    company.name = this.companyName;

    this.companyService.createCompany(company).subscribe(comp => {
       if (comp !== null) {
        this.employerAdminCompany = comp as Company;
      }
    });
  }

di mana perusahaan adalah objek entitas dalam aplikasi boot musim semi dan juga kelas di Angular.

export class Company {
    public id: number;
    public name: string;
    public owner: User;
    public locations: Array<Location>;
}
Maneesh Parihar
sumber