Làm cách nào để tôi truyền một đối tượng JSON đến một lớp bản thảo


393

Tôi đọc một đối tượng JSON từ một máy chủ REST từ xa. Đối tượng JSON này có tất cả các thuộc tính của một lớp bản thảo (theo thiết kế). Làm cách nào để tôi chuyển đối tượng JSON đã nhận thành một kiểu var?

Tôi không muốn điền var var (tức là có hàm tạo lấy đối tượng JSON này). Nó lớn và sao chép mọi thứ trên đối tượng phụ theo đối tượng phụ & thuộc tính theo thuộc tính sẽ mất rất nhiều thời gian.

Cập nhật: Tuy nhiên, bạn có thể chuyển nó sang giao diện bản thảo!


bạn có thể sử dụng github.com/vojtechhabarta/typescript-generator để tạo giao diện TypeScript trong trường hợp JSON của bạn được ánh xạ bằng các lớp Java
Vojta

Tôi đã mã hóa một thư viện truyền hình nhỏ: sulphur-blog.azurewebsites.net/typescript-mini-cast-l Library
Camille Wintz

1
Đối tượng JSON = Đối tượng ký hiệu đối tượng JavaScript. Không có đủ đồ vật trong đó, tôi nói chúng ta ném thêm một vài thứ nữa để có biện pháp tốt.
lỗi rất nhiều vào

1
Tôi đã tạo một công cụ cho beshanoe.github.io/json2ts
beshanoe

Tạo lớp TypeScript nguyên mẫu để xác định đối tượng của bạn sẽ không ảnh hưởng đến mã sản xuất thực. Hãy xem tệp JS đã biên dịch, tất cả các định nghĩa sẽ bị xóa, vì chúng không phải là một phần của JS.
FisNaN

Câu trả lời:


167

Bạn không thể đơn giản chuyển một kết quả JavaScript cũ đơn giản từ một yêu cầu Ajax thành một cá thể lớp JavaScript / TypeScript nguyên mẫu. Có một số kỹ thuật để thực hiện nó, và thường liên quan đến việc sao chép dữ liệu. Trừ khi bạn tạo một thể hiện của lớp, nó sẽ không có bất kỳ phương thức hoặc thuộc tính nào. Nó sẽ vẫn là một đối tượng JavaScript đơn giản.

Mặc dù nếu bạn chỉ xử lý dữ liệu, bạn chỉ có thể thực hiện chuyển giao sang giao diện (vì đó hoàn toàn là cấu trúc thời gian biên dịch), điều này sẽ yêu cầu bạn sử dụng lớp TypeScript sử dụng thể hiện dữ liệu và thực hiện các thao tác với dữ liệu đó.

Một số ví dụ về sao chép dữ liệu:

  1. Sao chép đối tượng AJAX JSON vào Đối tượng hiện có
  2. Phân tích chuỗi JSON thành một nguyên mẫu đối tượng cụ thể trong JavaScript

Về bản chất, bạn chỉ cần:

var d = new MyRichObject();
d.copyInto(jsonResult);

Tôi đồng ý với câu trả lời của bạn. Ngoài ra, mặc dù tôi không ở nơi để tìm kiếm và kiểm tra nó ngay bây giờ, tôi nghĩ rằng hai bước đó có thể được kết hợp bằng cách cung cấp chức năng đánh thức như một thông số JSON.parse(). Cả hai vẫn sẽ cần phải được thực hiện, nhưng về mặt cú pháp chúng có thể được kết hợp.
JAAulde

Chắc chắn, điều đó cũng có thể hoạt động - Tôi không có ý thức về việc liệu nó có hiệu quả hơn không vì nó sẽ cần phải gọi một cuộc gọi chức năng bổ sung cho mỗi thuộc tính.
WiredPrairi

Chắc chắn đó không phải là câu trả lời mà tôi đang tìm kiếm :( Vì tò mò tại sao lại như vậy? Dường như với tôi cách javascript hoạt động mà điều này nên làm được.
David Thielen

Không, nó không hoạt động trong TypeScript vì không có cách đơn giản nào trong JavaScript để làm điều này.
WiredPrairi

1
Thế cònObject.setPrototypeOf
Petah

102

Tôi đã có cùng một vấn đề và tôi đã tìm thấy một thư viện thực hiện công việc: https://github.com/pleerock/ class-transformer .

Nó hoạt động như thế này:

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

Nó hỗ trợ những đứa trẻ lồng nhau nhưng bạn phải trang trí thành viên trong lớp.


14
Thư viện nhỏ tuyệt vời này đã giải quyết nó một cách hoàn hảo với ít nỗ lực nhất (tuy nhiên đừng quên @Typechú thích của bạn ). Câu trả lời này xứng đáng được thêm tín dụng.
Benny Bottema

Ôi chà!, Thư viện này không quá nhỏ, nó có thể có mọi thứ bạn cần, thậm chí cho phép bạn kiểm soát sự biến đổi với trang trí @transform: D
Diego Fernando Murillo Valenci

3
Hãy lưu ý rằng thư viện này hầu như không được duy trì nữa. Nó không còn hoạt động với Angular5 + nữa và vì chúng thậm chí không hợp nhất các yêu cầu kéo nữa, tôi không nghĩ rằng chúng sẽ sớm hoạt động trên đó. Đó là một thư viện tuyệt vời mặc dù.
kentor

Có một cách giải quyết cho Angular5 + (thực ra là lỗi Angular): github.com/typestack/
Pak

2
Điều này chỉ hoạt động tốt trong Angular 6 (ít nhất là đối với trường hợp sử dụng của tôi, chỉ để ánh xạ theo nghĩa đen JSON <=> Class)
tftd

54

Trong TypeScript, bạn có thể thực hiện xác nhận kiểu bằng giao diện và chung chung như vậy:

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

Trong đó ILocationMap mô tả hình dạng của dữ liệu của bạn. Ưu điểm của phương thức này là JSON của bạn có thể chứa nhiều thuộc tính hơn nhưng hình dạng thỏa mãn các điều kiện của giao diện.

Tôi hy vọng điều đó sẽ giúp!


49
FYI: Đó là một khẳng định kiểu, không phải là diễn viên.
WiredPrairi

6
Xem ở đây để biết sự khác biệt giữa xác nhận loạidiễn viên .
Stefan Hanke

7
Tôi có thể tìm thấy tiện ích ở đâu.
HypeXR

22
Nhưng nó sẽ không có bất kỳ phương pháp nào, như đã đề cập trong câu trả lời.
Martín Coll

1
@StefanHanke có vẻ như URL đã thay đổi một chút: "Loại xác nhận so với đúc"
ruffin

37

Nếu bạn đang sử dụng ES6, hãy thử điều này:

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()
})

Nhưng cách này sẽ không hoạt động trên các đối tượng tổ , đáng buồn.


4
Họ yêu cầu nó trong Bản in.
joe.feser

HI @ joe.feser, tôi đề cập đến ES6 vì theo cách này, phương thức 'Object.assign' là bắt buộc.
mã hóa

1
Trong trường hợp hàm tạo mặc định bị thiếu, thể hiện đích có thể được tạo thông qua Object.create(MyClass.prototype), bỏ qua hoàn toàn hàm tạo.
Marcello

Giải thích thêm về giới hạn đối tượng lồng nhau, xem trong stackoverflow.com/questions/22885995/
triệt

28

Tôi đã tìm thấy một bài viết rất thú vị về việc đúc chung JSON cho Lớp Bản in:

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

Bạn kết thúc với mã sau đây:

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

20

TLDR: Một lớp lót

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

Câu trả lời chi tiết

Tôi sẽ không đề xuất cách tiếp cận Object.assign, vì nó có thể xả rác không đúng cách đối tượng lớp của bạn với các thuộc tính không liên quan (cũng như các bao đóng được xác định) không được khai báo trong chính lớp đó.

Trong lớp mà bạn đang cố gắng giải tuần tự hóa, tôi sẽ đảm bảo bất kỳ thuộc tính nào bạn muốn khử lưu lượng được xác định (null, mảng trống, v.v.). Bằng cách xác định các thuộc tính của bạn với các giá trị ban đầu, bạn sẽ hiển thị mức độ hiển thị của chúng khi cố gắng lặp lại các thành viên của lớp để gán giá trị cho (xem phương thức deserialize bên dưới).

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];
      }
    }
  }
}

Trong ví dụ trên, tôi chỉ đơn giản tạo ra một phương thức deserialize. Trong một ví dụ thực tế, tôi sẽ tập trung vào lớp cơ sở hoặc phương thức dịch vụ có thể sử dụng lại.

Đây là cách sử dụng cái này trong một cái gì đó như http resp ...

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

Nếu tslint / ide phàn nàn về loại đối số không tương thích, chỉ cần chuyển đối số thành cùng loại bằng dấu ngoặc nhọn <YourClassName>, ví dụ:

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

Nếu bạn có các thành viên lớp thuộc một loại cụ thể (hay còn gọi là thể hiện của một lớp khác), thì bạn có thể đưa chúng vào các thể hiện được gõ thông qua các phương thức getter / setter.

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));
  }
}

Ví dụ trên sẽ giải tuần tự hóa cả acct và danh sách các nhiệm vụ vào các thể hiện lớp tương ứng của chúng.


Tôi nhận được thông báo lỗi này: Loại '{name: chuỗi, age: number, id: number}' không thể được chuyển đổi thành loại 'Person'. Thuộc tính 'id' là riêng tư trong loại 'Người' nhưng không thuộc loại '{tên: chuỗi, tuổi: số, id: số}'
utiq

Làm thế nào tôi nên sử dụng này với enums? Tôi có phải sử dụng cách tiếp cận kiểu cụ thể và thêm getter và setter cho nó không?
Tadija Bagarić

@TimothyParez Khi nào bạn đặt nhiệm vụ?
Kay

Tôi đã cố gắng làm một cái gì đó tương tự nhưng mảng nhiệm vụ của tôi trống khi tôi console.log người.
Kay

Để biên dịch, tôi phải thêm Chữ ký chỉ mục vào lớp: lớp xuất khẩu Person {[key: string]: any (...)}
Asimov

18

Giả sử json có các thuộc tính giống như lớp bản thảo của bạn, bạn không phải sao chép các thuộc tính Json của mình vào đối tượng bản thảo. Bạn sẽ chỉ phải xây dựng đối tượng Bản mô tả của mình truyền dữ liệu json trong hàm tạo.

Trong cuộc gọi lại ajax của bạn, bạn nhận được một công ty:

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

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

Để thực hiện công việc đó:

1) Thêm một hàm tạo trong lớp Typecript lấy dữ liệu json làm tham số. Trong hàm tạo đó, bạn mở rộng đối tượng json của mình bằng jQuery, như thế này : $.extend( this, jsonData). $ .extend cho phép giữ nguyên mẫu javascript trong khi thêm thuộc tính của đối tượng json.

2) Lưu ý bạn sẽ phải làm tương tự cho các đối tượng được liên kết. Trong trường hợp Nhân viên trong ví dụ, bạn cũng tạo một hàm tạo lấy phần dữ liệu json cho nhân viên. Bạn gọi $ .map để dịch nhân viên json sang các đối tượng Nhân viên bản thảo.

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);
    }
}

Đây là giải pháp tốt nhất tôi tìm thấy khi xử lý các lớp typecript và các đối tượng json.


Tôi thích giải pháp này hơn là triển khai và duy trì giao diện, vì các ứng dụng Angular2 của tôi có mô hình ứng dụng thực tế có thể khác với mô hình dịch vụ web mà ứng dụng của tôi sử dụng. Nó có thể có dữ liệu riêng tư và các thuộc tính được tính toán.
Anthony Brenelière

7
Sử dụng JQuery trong các dự án Angular là một ý tưởng tồi tệ. Và nếu các mô hình của bạn chứa một loạt các chức năng trên chúng, chúng không còn là các mô hình nữa.
Thưởng thức

1
@Davor Ý bạn là POJO, hay người mẫu? POJO (về cơ bản là các đối tượng đơn giản) không có chức năng, trong khi mô hình là một thuật ngữ rộng hơn và nó bao gồm kho lưu trữ. Mẫu lưu trữ, trái ngược với POJO, là về các chức năng, nhưng nó vẫn là mô hình.
forsberg

@Davor: sử dụng JQuery trong các dự án Angular không phải là ý tưởng tồi miễn là bạn không sử dụng nó để thao túng DOM, đây thực sự là một ý tưởng tồi tệ. Tôi sử dụng bất kỳ thư viện nào tôi cần cho các dự án Angular của mình và đối với jQuery thì đó không phải là một tùy chọn vì dự án của tôi sử dụng SignalR phụ thuộc vào nó. Trong trường hợp các lớp, hiện được sử dụng bởi javascript ES6, dữ liệu được truy cập với các thuộc tính là hàm đóng gói cách lưu trữ dữ liệu trong bộ nhớ. Đối với các nhà xây dựng, có một cách thích hợp mà sử dụng các nhà máy.
Anthony Brenelière

OP rõ ràng là về các mô hình dữ liệu đơn giản cho REST. Bạn đang làm cho nó phức tạp không cần thiết, các bạn. Và vâng, bạn có thể sử dụng Jquery cho các công cụ bổ sung, nhưng bạn đang nhập một thư viện lớn để sử dụng 1% trong số đó. Đó là mùi mã nếu tôi từng thấy.
Thưởng thức

18

Vẫn chưa có gì để tự động kiểm tra xem đối tượng JSON mà bạn nhận được từ máy chủ có thuộc tính giao diện dự kiến ​​(đọc có phù hợp với) không. Nhưng bạn có thể sử dụng Bảo vệ Loại do Người dùng Xác định

Xem xét giao diện sau đây và một đối tượng json ngớ ngẩn (nó có thể là bất kỳ loại nào):

interface MyInterface {
    key: string;
 }

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

Ba cách có thể:

A. Xác nhận kiểu hoặc ép tĩnh đơn giản được đặt sau biến

const myObject: MyInterface = json as MyInterface;

B. Đúc tĩnh đơn giản, trước biến và giữa kim cương

const myObject: MyInterface = <MyInterface>json;

C. Diễn viên động tiên tiến, bạn tự kiểm tra cấu trúc của đối tượng

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}'.`);
}

Bạn có thể chơi với ví dụ này ở đây

Lưu ý rằng khó khăn ở đây là viết isMyInterfacehàm. Tôi hy vọng TS sẽ sớm thêm một trình trang trí để xuất kiểu gõ phức tạp vào thời gian chạy và để thời gian chạy kiểm tra cấu trúc của đối tượng khi cần. Hiện tại, bạn có thể sử dụng trình xác thực lược đồ json với mục đích gần giống với HOẶC trình tạo chức năng kiểm tra loại thời gian chạy này


1
Câu trả lời của bạn nên được đặt lên hàng đầu tôi nghĩ
afzalex

Chắc chắn rồi. Đây là câu trả lời tốt nhất dựa trực tiếp vào trang web ts.
Burak Karakuş

15

Trong trường hợp của tôi, nó hoạt động. Tôi đã sử dụng các hàm Object.assign (đích, nguồn ...) . Đầu tiên, tạo đối tượng chính xác, sau đó sao chép dữ liệu từ đối tượng json sang đích. Ví dụ:

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

Và một ví dụ nâng cao hơn về việc sử dụng. Một ví dụ sử dụng mảng.

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;
  }
}

Điều gì xảy ra khi bạn có một tài sản riêng?
prasanthv

Bởi vì đối tượng jsonUser không phải là lớp Người dùng. Không có hoạt động Object.assign (u, jsonUsers); Bạn không thể sử dụng hàm getId (). Chỉ sau khi gán, bạn mới có được một đối tượng Người dùng hợp lệ trong đó bạn có thể sử dụng hàm getId (). Hàm getId () chỉ dành cho ví dụ rằng thao tác đã thành công.
Adam111p

bạn có thể bỏ qua var temp - chỉ cần làmthis.users[i] = new User(); Object.assign(this.users[i], users[i])
cyptus

hoặc thậm chí tốt hơn là sử dụng giá trị trả về:this.users[i] = Object.assign(new User(), users[i]);
cyptus

Phiên bản dài này chỉ để giải thích. Bạn có thể rút ngắn mã bao nhiêu tùy thích :)
Adam111p

6

Trong khi nó không phải là đúc mỗi se; Tôi đã tìm thấy https://github.com/JohnWhiteTB/TypedJSON là một thay thế hữu ích.

@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"

1
Nó không đúc, nó thực sự làm gì?
DanielM

1
Giải pháp này đòi hỏi rất nhiều chú thích. Có thực sự không có cách dễ dàng hơn?
JPNotADragon

3

Bạn có thể tạo một interfacekiểu của bạn ( SomeType) và bỏ đối tượng vào đó.

const typedObject: SomeType = <SomeType> responseObject;

3

Nếu bạn cần truyền đối tượng json của mình vào một lớp bản thảo và có sẵn các phương thức cá thể của nó trong đối tượng kết quả mà bạn cần sử dụng Object.setPrototypeOf, giống như tôi đã làm trong đoạn mã dưới đây:

Object.setPrototypeOf(jsonObject, YourTypescriptClass.prototype)

2

Một câu hỏi cũ với hầu hết các câu trả lời đúng, nhưng không hiệu quả. Đây là những gì tôi đề xuất:

Tạo một lớp cơ sở chứa phương thức init () và các phương thức truyền tĩnh (cho một đối tượng và một mảng). Các phương thức tĩnh có thể ở bất cứ đâu; phiên bản với lớp cơ sở và init () cho phép mở rộng dễ dàng sau đó.

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() { }
}

Cơ học tương tự (với gán () ) đã được đề cập trong bài đăng @ Adam111p. Chỉ là một cách khác (đầy đủ hơn) để làm điều đó. @Timothy Perez rất quan trọng về gán () , nhưng imho nó hoàn toàn thích hợp ở đây.

Thực hiện một lớp dẫn xuất (thực):

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);
        }
    }
}

Bây giờ chúng ta có thể truyền một đối tượng được lấy từ dịch vụ:

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

Tất cả hệ thống phân cấp của các đối tượng SubjectArea sẽ có lớp chính xác.

Một trường hợp sử dụng / ví dụ; tạo một dịch vụ Angular (lớp cơ sở trừu tượng một lần nữa):

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;
  }
}

Việc sử dụng trở nên rất đơn giản; tạo một dịch vụ Khu vực:

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

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

Phương thức get () của dịch vụ sẽ trả về một Promise của một mảng đã được truyền dưới dạng các đối tượng SubjectArea (toàn bộ phân cấp)

Bây giờ nói, chúng tôi có một lớp khác:

export class OtherItem extends ContentItem {...}

Tạo một dịch vụ lấy dữ liệu và chuyển sang đúng lớp cũng đơn giản như:

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

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

2

Sử dụng một lớp mở rộng từ một giao diện.

Sau đó:

Object.assign(
                new ToWhat(),
                what
              )

Và tốt nhất:

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

ToWhat trở thành bộ điều khiển của DataInterface.


1

https://jvilk.com/MakeTypes/

bạn có thể sử dụng trang này để tạo proxy cho bạn. nó tạo ra một lớp và có thể phân tích cú pháp và xác thực đối tượng JSON đầu vào của bạn.


0

Trong lates TS bạn có thể làm như thế này:

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

Và hơn người dùng như thế này:

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

0

Tôi chạy vào một nhu cầu tương tự. Tôi muốn một cái gì đó sẽ giúp tôi chuyển đổi dễ dàng từ / sang JSON đến từ một lệnh gọi api REST đến / từ định nghĩa lớp cụ thể. Các giải pháp mà tôi tìm thấy là không đủ hoặc có nghĩa là viết lại mã của lớp tôi và thêm chú thích hoặc mô phỏng.

Tôi muốn một cái gì đó giống như GSON được sử dụng trong Java để tuần tự hóa / giải tuần tự hóa các lớp đến / từ các đối tượng JSON.

Kết hợp với nhu cầu sau này, bộ chuyển đổi cũng sẽ hoạt động trong JS, tôi đã kết thúc việc viết gói của riêng mình.

Nó có mặc dù, một chút chi phí. Nhưng khi bắt đầu, nó rất thuận tiện trong việc thêm và chỉnh sửa.

Bạn khởi tạo mô-đun bằng:

  1. lược đồ chuyển đổi - cho phép ánh xạ giữa các trường và xác định cách chuyển đổi sẽ được thực hiện
  2. Mảng bản đồ lớp
  3. Bản đồ chức năng chuyển đổi - cho các chuyển đổi đặc biệt.

Sau đó, trong mã của bạn, bạn sử dụng mô-đun khởi tạo như:

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

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

hoặc, đến JSON:

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

Sử dụng liên kết này đến gói npm và cũng là một lời giải thích chi tiết về cách làm việc với mô-đun: json-class-convert

Cũng gói nó để
sử dụng Angular trong: angular-json-class-convert


0

Truyền đối tượng như là cho trình xây dựng lớp; Không có quy ước hoặc kiểm tra

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

0

Bạn có thể sử dụng gói npm này. https://www.npmjs.com/package/ class-converter

Nó rất dễ sử dụng, ví dụ:

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',
// }

0

Cá nhân tôi thấy thật kinh khủng khi bản thảo không cho phép định nghĩa điểm cuối chỉ định loại đối tượng được nhận. Vì có vẻ như đây thực sự là trường hợp, tôi sẽ làm những gì tôi đã làm với các ngôn ngữ khác và đó là tôi sẽ tách đối tượng JSON khỏi định nghĩa lớp và định nghĩa lớp sử dụng đối tượng JSON làm thành viên dữ liệu duy nhất của nó .

Tôi coi thường mã soạn sẵn, vì vậy đối với tôi, vấn đề thường là đạt được kết quả mong muốn với số lượng mã ít nhất trong khi bảo quản loại.

Hãy xem xét các định nghĩa cấu trúc đối tượng JSON sau đây - đây sẽ là những gì bạn sẽ nhận được ở điểm cuối, chúng chỉ là định nghĩa cấu trúc, không có phương thức.

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

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

Nếu chúng ta nghĩ về điều trên theo thuật ngữ hướng đối tượng, các giao diện trên không phải là các lớp vì chúng chỉ xác định cấu trúc dữ liệu. Một lớp trong các thuật ngữ OO định nghĩa dữ liệu và mã hoạt động trên nó.

Vì vậy, bây giờ chúng ta định nghĩa một lớp chỉ định dữ liệu và mã hoạt động trên nó ...

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;
    }
}

Và bây giờ chúng ta có thể đơn giản vượt qua trong bất kỳ đối tượng nào phù hợp với cấu trúc IPerson và đang trên đường ...

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

Theo cách tương tự, bây giờ chúng ta có thể xử lý đối tượng nhận được tại điểm cuối của bạn bằng một cái gì đó dọc theo dòng ...

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

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

Điều này hiệu quả hơn nhiều và sử dụng một nửa bộ nhớ sao chép dữ liệu, đồng thời giảm đáng kể số lượng mã soạn sẵn mà bạn phải viết cho mỗi loại thực thể. Nó chỉ đơn giản dựa vào loại an toàn được cung cấp bởi TypeScript.



-1

Đây là một lựa chọn đơn giản và thực sự tốt

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

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

Và sau đó bạn sẽ có

objectConverted.name

-1

Tôi đã sử dụng thư viện này tại đây: https://github.com/pleerock/ class-transformer

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

Thực hiện:

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

Đôi khi bạn sẽ phải phân tích các giá trị JSON cho plainToClass để hiểu rằng đó là dữ liệu được định dạng JSON


Thư viện 'biến áp lớp' đã được đề xuất trong câu trả lời khác ở trên stackoverflow.com/a/40042282/52277
Michael Freidgeim

-1

Tôi đang sử dụng Angular 6 trên ứng dụng frontend và Spring Boot trên phần phụ trợ trả về các Đối tượng Java. Tất cả những gì tôi cần làm là định nghĩa một lớp tương tự trên ứng dụng góc có các thuộc tính khớp và sau đó tôi có thể chấp nhận đối tượng 'là' một đối tượng lớp góc ( ví dụ như Công ty trong ví dụ dưới đây).

Tham khảo mã mặt trước dưới đây chẳng hạn. Hãy cho tôi biết trong các ý kiến ​​nếu bất cứ điều gì cần rõ ràng hơn.

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

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

trong đó công ty là một đối tượng thực thể trong ứng dụng khởi động mùa xuân và cũng là một lớp trong Angular.

export class Company {
    public id: number;
    public name: string;
    public owner: User;
    public locations: Array<Location>;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.