[json] JSON 객체를 typescript 클래스로 캐스트하는 방법

원격 REST 서버에서 JSON 객체를 읽습니다. 이 JSON 객체에는 디자인에 따라 유형 스크립트 클래스의 모든 속성이 있습니다. 수신 된 JSON 객체를 유형 var로 캐스트하는 방법

타입 스크립트 var를 채우고 싶지 않습니다 (즉,이 JSON 객체를 취하는 생성자가 있습니다). 크기가 크며 하위 개체 및 속성별로 속성을 복사하는 데 많은 시간이 걸립니다.

업데이트 : 그러나 타이프 스크립트 인터페이스로 캐스트 할 수 있습니다 !



답변

Ajax 요청의 일반 오래된 JavaScript 결과를 프로토 타입 JavaScript / TypeScript 클래스 인스턴스로 간단히 캐스트 할 수 없습니다. 이를 수행하는 데는 여러 가지 기술이 있으며 일반적으로 데이터 복사가 필요합니다. 클래스의 인스턴스를 만들지 않으면 메서드 나 속성이 없습니다. 간단한 JavaScript 객체로 유지됩니다.

데이터 만 다루는 경우 인터페이스에 캐스트를 수행 할 수 있지만 (순전히 컴파일 시간 구조이므로) 데이터 인스턴스를 사용하고 해당 데이터에 대한 작업을 수행하는 TypeScript 클래스를 사용해야합니다.

데이터 복사의 몇 가지 예 :

  1. 기존 객체로 AJAX JSON 객체 복사
  2. JavaScript에서 JSON 문자열을 특정 객체 프로토 타입으로 구문 분석

본질적으로, 당신은 단지 :

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


답변

나는 같은 문제가 있었고 https://github.com/pleerock/class-transformer 작업을 수행하는 라이브러리를 찾았습니다 .

다음과 같이 작동합니다.

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

중첩 된 자식을 지원하지만 클래스 멤버를 장식해야합니다.


답변

TypeScript에서는 다음 과 같은 인터페이스와 제네릭을 사용하여 형식 어설 션 을 수행 할 수 있습니다 .

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

여기서 ILocationMap은 데이터 모양을 설명합니다. 이 방법의 장점은 JSON에 더 많은 속성을 포함 할 수 있지만 모양이 인터페이스의 조건을 충족한다는 것입니다.

도움이 되길 바랍니다.


답변

ES6를 사용하는 경우 다음을 시도하십시오.

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

그러나 슬프게도이 방법 은 중첩 객체 에서 작동하지 않습니다 .


답변

JSON을 Typescript 클래스로 일반 캐스팅하는 것에 대한 매우 흥미로운 기사를 찾았습니다.

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

다음 코드로 끝납니다.

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


답변

TLDR : 하나의 라이너

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

자세한 답변

나는 것 없는 이 클래스 자체 내에서 부적절 쓰레기 수업 관련이없는 속성이 예 (뿐만 아니라 정의 폐쇄) 선언되지 않은 수대로 Object.assign 방법을 추천합니다.

역 직렬화하려는 클래스에서 역 직렬화하려는 속성이 정의되어 있는지 확인합니다 (null, empty array 등). 초기 값으로 속성을 정의하면 클래스 멤버를 반복하여 값을 할당하려고 할 때 가시성을 노출합니다 (아래의 직렬화 해제 방법 참조).

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

위의 예에서 간단히 deserialize 메서드를 만들었습니다. 실제 예에서는 재사용 가능한 기본 클래스 또는 서비스 방법으로 중앙 집중화해야합니다.

여기에 http resp와 같은 것을 사용하는 방법이 있습니다 …

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

tslint / ide가 인수 유형이 호환되지 않는다고 불평하는 경우, 꺾쇠 괄호를 사용하여 인수를 동일한 유형으로 캐스트하십시오 ( <YourClassName>예 :

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

특정 유형의 클래스 멤버 (일명 : 다른 클래스의 인스턴스)가있는 경우 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));
  }
}

위의 예제는 acct와 작업 목록을 각각의 클래스 인스턴스로 역 직렬화합니다.


답변

json에 typescript 클래스와 동일한 속성이 있다고 가정하면 Json 속성을 typescript 객체에 복사 할 필요가 없습니다. 생성자에서 json 데이터를 전달하는 Typescript 객체를 구성해야합니다.

Ajax 콜백에서 회사를받습니다 :

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

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

그 일을하기 위해 :

1) json 데이터를 매개 변수로 사용하는 생성자를 Typescript 클래스에 추가하십시오. 해당 생성자에서 다음과 같이 jQuery로 json 객체를 확장합니다 $.extend( this, jsonData). $ .extend를 사용하면 json 객체의 속성을 추가하면서 자바 스크립트 프로토 타입을 유지할 수 있습니다.

2) 연결된 객체에 대해서도 동일한 작업을 수행해야합니다. 예제의 Employees의 경우 직원에 대한 json 데이터의 일부를 사용하는 생성자를 작성하십시오. json 직원을 typescript Employee 객체로 변환하려면 $ .map을 호출하십시오.

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

이것이 Typescript 클래스와 json 객체를 다룰 때 찾은 최고의 솔루션입니다.