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


393

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

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

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


자바 클래스를 사용하여 JSON이 매핑 된 경우 github.com/vojtechhabarta/typescript-generator 를 사용 하여 TypeScript 인터페이스를 생성 할 수 있습니다.
Vojta

나는 작은 캐스팅 라이브러리를 코딩했습니다 : sulphur-blog.azurewebsites.net/typescript-mini-cast-library
Camille Wintz

1
JSON 객체 = JavaScript 객체 표기법 객체. 거기에 물건이 충분하지 않다면, 나는 우리가 더 잘 측정하기 위해 몇 가지를 던진다 고 말합니다.
bug-a-lot


객체를 정의하기 위해 프로토 타입 TypeScript 클래스를 생성해도 실제 프로덕션 코드는 손상되지 않습니다. 컴파일 된 JS 파일을 살펴보십시오. 모든 정의는 JS의 일부가 아니므로 제거됩니다.
FisNaN

답변:


167

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

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

데이터 복사의 몇 가지 예 :

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

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

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

나는 당신의 대답에 동의합니다. 또한 지금은 찾아보고 테스트 할 위치가 아니지만이 두 단계를에 대한 매개 변수로 깨우기 기능을 제공하여 결합 할 수 있다고 생각합니다 JSON.parse(). 둘 다 여전히 수행해야하지만 구문 적으로 결합 할 수 있습니다.
JAAulde

물론 작동 할 수도 있습니다. 각 속성에 대해 추가 함수 호출을 호출해야하므로 더 효율적인지 여부는 알 수 없습니다.
WiredPrairie

? I가 :( 호기심에서보고 있었다 확실히 대답은 이유입니다 방법의 자바 스크립트이 행할해야한다고 작동 날 것으로 보인다.
데이비드 티 엘렌

아니요, JavaScript에는 간단한 방법이 없기 때문에 TypeScript에서는 작동하지 않습니다.
WiredPrairie

1
어떻습니까Object.setPrototypeOf
Petah

102

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

다음과 같이 작동합니다.

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

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


14
이 훌륭한 작은 라이브러리는 최소한의 노력으로 완벽하게 해결했습니다 ( @Type그러나 주석을 잊지 마십시오 ). 이 답변에는 더 많은 크레딧이 필요합니다.
베니 보 테마

D : 오 와우!,이 라이브러리는 심지어 당신이 @transform 데코레이터로 변환을 제어 할 수 있습니다, 아니 당신이 필요 어쩌면 모든 것을 가지고 너무 작다
디에고 페르난도 무리 요 Valenci

3
이 라이브러리는 더 이상 거의 유지되지 않습니다. 더 이상 Angular5 +에서는 작동하지 않으며 풀 요청을 더 이상 병합하지 않기 때문에 곧 작동하지 않을 것이라고 생각합니다. 그래도 훌륭한 도서관입니다.
kentor

Angular5 +에 대한 해결 방법이 있습니다 (실제로는 Angular Bug입니다) : github.com/typestack/class-transformer/issues/108
Pak

2
이것은 Angular 6에서 잘 작동합니다 (적어도 문자 그대로 JSON <=> 클래스를 매핑하는 유스 케이스의 경우)
tftd

54

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

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

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

도움이 되길 바랍니다.


49
참고 : 캐스트가 아닌 형식 어설 션입니다.
WiredPrairie

6
형식 어설 션캐스트 의 차이점 은 여기 를 참조 하십시오 .
Stefan Hanke

7
Utilities.JSONLoader는 어디에서 찾을 수 있습니까?
HypeXR

22
그러나 대답에 언급 된 것처럼 방법이 없습니다.
Martín Coll

1
@StefanHanke는 URL이 약간 변경된 것 같습니다 : "유형 어설 션 대 캐스팅"
ruffin

37

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

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


4
그들은 Typescript로 요청했습니다.
joe.feser

안녕 @ joe.feser, 나는 'Object.assign'메소드가 필요하기 때문에 ES6을 언급했다.
migcoder

1
기본 생성자가없는 경우 생성자를 Object.create(MyClass.prototype)무시하고 대상 인스턴스를 통해 생성 할 수 있습니다 .
Marcello

중첩 객체 제한에 대한 자세한 설명은 stackoverflow.com/questions/22885995/…를
Michael Freidgeim

28

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

20

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와 작업 목록을 각각의 클래스 인스턴스로 역 직렬화합니다.


이 오류 메시지가 나타납니다. '{name : string, age : number, id : number}'유형을 'Person'유형으로 변환 할 수 없습니다. 'id'속성은 'Person'유형에 비공개이지만 '{name : string, age : number, id : number}'
유형에 속하지 않음

열거 형과 함께 이것을 어떻게 사용해야합니까? 특정 유형의 접근 방식을 사용해야하고 getter 및 setter를 추가해야합니까?
Tadija Bagarić '11

@TimothyParez 언제 작업을 설정합니까?
Kay

나는 비슷한 것을 시도했지만 console.log person 일 때 내 작업 배열이 비어 있습니다.
Kay

이것을 컴파일하려면 클래스에 인덱스 서명을 추가해야했습니다. export class Person {[key : string] : any (...)}
Asimov

18

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 객체를 다룰 때 찾은 최고의 솔루션입니다.


Angular2 응용 프로그램에는 응용 프로그램이 사용하는 웹 서비스 모델과 다를 수있는 실제 응용 프로그램 모델이 있으므로 인터페이스 구현 및 유지 관리보다이 솔루션을 선호합니다. 개인 데이터와 계산 된 속성을 가질 수 있습니다.
Anthony Brenelière

7
Angular 프로젝트에서 JQuery를 사용하는 것은 끔찍한 아이디어입니다. 그리고 모델에 많은 기능이 포함되어 있으면 더 이상 모델이 아닙니다.
Davor

1
@Davor 당신은 POJO, 또는 모델을 의미합니까? POJO (기본적으로 일반 객체)에는 기능이 없지만 모델은 더 넓은 용어이며 리포지토리를 포함합니다. POJO와 달리 저장소 패턴은 함수에 관한 것이지만 여전히 모델입니다.
forsberg

@Davor : Angular 프로젝트에서 JQuery를 사용하는 것이 DOM을 조작하는 데 사용하지 않는 한 나쁜 생각은 아닙니다. 실제로는 끔찍한 생각입니다. Angular 프로젝트에 필요한 라이브러리를 사용하고 있으며 jQuery의 경우 프로젝트에 의존하는 SignalR을 사용하기 때문에 옵션이 아닙니다. 이제 자바 스크립트 ES6에서 사용하는 클래스의 경우 데이터가 메모리에 저장되는 방식을 캡슐화하는 기능인 속성을 사용하여 데이터에 액세스합니다. 생성자에는 팩토리를 사용하는 적절한 방법이 있습니다.
Anthony Brenelière

OP는 분명히 REST의 일반 데이터 모델에 관한 것입니다. 당신은 그것을 불필요하게 복잡하게 만들고 있습니다. 그리고 예, Jquery를 사용하여 추가 자료를 사용할 수 있지만 1 %를 사용하기 위해 대규모 라이브러리를 가져오고 있습니다. 내가 본 적이 있다면 코드 냄새입니다.
Davor

18

서버에서 수신 한 JSON 오브젝트에 예상 한 (읽기 준수) 유형 스크립트의 인터페이스 특성이 있는지 자동으로 확인할 것은 없습니다. 그러나 사용자 정의 유형 가드를 사용할 수 있습니다

다음 인터페이스와 바보 같은 json 객체 (모든 유형 일 수 있음)를 고려하십시오.

interface MyInterface {
    key: string;
 }

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

세 가지 가능한 방법 :

A. 변수 뒤에 놓인 Type Assertion 또는 단순 정적 캐스트

const myObject: MyInterface = json as MyInterface;

B. 변수 앞과 다이아몬드 사이의 간단한 정적 캐스트

const myObject: MyInterface = <MyInterface>json;

C. 고급 다이나믹 캐스트, 물체의 구조를 직접 확인하십시오.

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

이 예제를 가지고 놀 수 있습니다

여기서 어려움은 isMyInterface함수 를 작성하는 것입니다. TS가 장식자를 조만간 추가 하여 런타임에 복잡한 타이핑내보내고 런타임이 필요할 때 객체의 구조를 확인하도록하겠습니다. 지금까지는 거의 동일한 목적 또는이 런타임 유형 검사 함수 생성기 인 JSON 스키마 유효성 검증기를 사용할 수 있습니다.


1
귀하의 답변은 내가 생각하는 최상위에 있어야합니다
afzalex

명확히. 이것은 ts 웹 사이트에 직접 의존하는 가장 좋은 대답입니다.
Burak Karakuş

15

제 경우에는 효과가 있습니다. Object.assign (target, sources ...) 함수를 사용했습니다 . 먼저 올바른 객체를 만든 다음 json 객체에서 대상으로 데이터를 복사합니다.

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

그리고 고급 사용 예입니다. 배열을 사용한 예입니다.

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

개인 재산이 있으면 어떻게됩니까?
prasanthv

jsonUser 객체는 User 클래스가 아니기 때문입니다. 조작이 없으면 Object.assign (u, jsonUsers); getId () 함수를 사용할 수 없습니다. 할당 후에 만 ​​getId () 함수를 사용할 수있는 유효한 User 객체를 얻습니다. getId () 함수는 작업이 성공한 예제에만 해당됩니다.
Adam111p

당신은 임시 var를 건너 뛸 수 있습니다 – 그냥this.users[i] = new User(); Object.assign(this.users[i], users[i])
cyptus

또는 반환 값을 더 잘 활용하십시오.this.users[i] = Object.assign(new User(), users[i]);
cyptus

이 긴 버전은 설명을위한 것입니다. 원하는만큼 코드를 줄일 수 있습니다 :)
Adam111p

6

그것이 캐스팅되지 않는 동안; https://github.com/JohnWhiteTB/TypedJSON 이 유용한 대안이라는 것을 알았습니다 .

@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
주조하지 않고 실제로 무엇을합니까?
DanielM

1
이 솔루션에는 많은 주석이 필요합니다. 더 쉬운 방법이 없습니까?
JPNotADragon

3

interface유형 ( SomeType)을 생성하고 그 안에 객체를 캐스트 할 수 있습니다 .

const typedObject: SomeType = <SomeType> responseObject;

3

json 객체를 typescript 클래스로 캐스팅하고 결과 객체에서 인스턴스 메소드를 사용할 수 있어야하는 경우 Object.setPrototypeOf코드 스 니펫 벨로우즈에서와 같이 사용해야합니다 .

Object.setPrototypeOf(jsonObject, YourTypescriptClass.prototype)

2

대부분 정확하지만 매우 효율적인 답변이없는 오래된 질문입니다. 이것이 내가 제안하는 것 :

init () 메소드와 정적 캐스트 메소드 (단일 오브젝트 및 배열) 를 포함하는 기본 클래스를 작성하십시오 . 정적 메소드는 어디에나있을 수 있습니다. 기본 클래스와 init ()가 있는 버전은 나중에 쉽게 확장 할 수 있습니다.

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

@ Adam111p post에서 이와 유사한 역학 ( assign () 사용 )이 언급되었습니다. 또 다른 (보다 완전한) 방법입니다. @Timothy Perez는 assign ()의 중요 하게 여기지만 imho는 여기에 완전히 적합합니다.

파생 (실제) 클래스를 구현하십시오.

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

이제 서비스에서 검색 한 객체를 캐스트 할 수 있습니다.

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

SubjectArea 객체 의 모든 계층 에는 올바른 클래스가 있습니다.

사용 사례 / 예; Angular 서비스를 작성하십시오 (기본 클래스를 다시 추상화하십시오).

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

사용법이 매우 간단 해집니다. 영역 서비스를 작성하십시오.

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

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

서비스의 get () 메소드는 이미 SubjectArea 객체 로 캐스트 된 배열의 약속을 반환 합니다 (전체 계층 구조)

이제 또 다른 수업이 있습니다.

export class OtherItem extends ContentItem {...}

데이터를 검색하고 올바른 클래스로 캐스트하는 서비스 작성은 다음과 같이 간단합니다.

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

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

2

인터페이스에서 확장 된 클래스를 사용하십시오.

그때:

Object.assign(
                new ToWhat(),
                what
              )

그리고 최고 :

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

ToWhat는 DataInterface의 컨트롤러가됩니다.



0

늦은 TS에서는 다음과 같이 할 수 있습니다.

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

그리고이 같은 사용자보다 :

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

0

나는 비슷한 요구에 부딪쳤다. REST API 호출에서 특정 클래스 정의로 또는 JSON에서 오는 JSON으로 쉽게 변환 할 수있는 것을 원했습니다. 내가 찾은 솔루션이 불충분하거나 클래스 코드를 다시 작성하고 주석 또는 유사한 것을 추가하기위한 것입니다.

Java에서 GSON과 같은 클래스를 사용하여 JSON 객체와 클래스를 직렬화 / 직렬화 해제하고 싶었습니다.

이후의 요구와 함께 변환기가 JS에서도 작동해야한다는 내 자신의 패키지 작성을 마쳤습니다.

그러나 약간의 오버 헤드가 있습니다. 그러나 시작되면 추가 및 편집이 매우 편리합니다.

다음을 사용하여 모듈을 초기화하십시오.

  1. 변환 스키마-필드 간 매핑 및 변환 수행 방법 결정
  2. 클래스 맵 배열
  3. 변환 함수 맵-특수 변환 용.

그런 다음 코드에서 초기화 된 모듈을 다음과 같이 사용합니다.

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

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

또는 JSON으로 :

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

이 링크를 npm 패키지 및 모듈 작업 방법에 대한 자세한 설명을 사용하십시오. json-class-converter

또한 angular-json-class-converter
에서 Angular 사용을 위해 랩핑했습니다 .


0

객체를 그대로 클래스 생성자에 전달하십시오. 컨벤션이나 수표 없음

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

이 npm 패키지를 사용할 수 있습니다. https://www.npmjs.com/package/class-converter

예를 들어 사용하기 쉽습니다.

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

개인적으로 typescript가 엔드 포인트 정의가 수신중인 오브젝트의 유형을 지정하도록 허용하지 않는다는 사실을 알게되었습니다. 이것이 사실 인 것처럼, 나는 다른 언어로 한 일을 할 것입니다. 즉, JSON 객체를 클래스 정의와 분리하고 클래스 정의가 JSON 객체를 유일한 데이터 멤버로 사용하게합니다 .

나는 상용구 코드를 멸시하므로 일반적으로 유형을 유지하면서 가장 적은 양의 코드로 원하는 결과를 얻는 것이 중요합니다.

다음 JSON 오브젝트 구조 정의를 고려하십시오. 이는 엔드 포인트에서 수신되는 것이며 구조 정의 일 뿐이며 메소드는 없습니다.

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

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

위의 객체 지향 용어로 생각하면 위의 인터페이스는 데이터 구조 만 정의하기 때문에 클래스가 아닙니다. OO 용어의 클래스는 데이터와 그에 작동하는 코드를 정의합니다.

이제 데이터와 데이터를 처리하는 코드를 지정하는 클래스를 정의합니다.

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

이제 IPerson 구조를 준수하는 모든 객체를 전달하고 진행할 수 있습니다.

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

같은 방식으로 엔드 포인트에서 수신 한 객체를 라인을 따라 처리 할 수 ​​있습니다.

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

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

이것은 훨씬 더 성능이 좋으며 데이터 복사 메모리의 절반을 사용하는 동시에 각 엔티티 유형에 대해 작성해야하는 상용구 코드의 양을 크게 줄입니다. 단순히 TypeScript가 제공하는 형식 안전성에 의존합니다.



-1

이것은 간단하고 정말 좋은 옵션입니다

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

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

그리고 당신은 할 것이다

objectConverted.name

-1

나는이 라이브러리를 여기에서 사용했다 : https://github.com/pleerock/class-transformer

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

이행:

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

때로는 plainToClass가 JSON 형식의 데이터임을 이해하기 위해 JSON 값을 구문 분석해야합니다.


'class-transformer'라이브러리는 이미 stackoverflow.com/a/40042282/52277
Michael Freidgeim

-1

Java 객체를 반환하는 백엔드의 프론트 엔드 및 스프링 부트 응용 프로그램에서 Angular 6을 사용하고 있습니다. 내가해야 할 일은 일치하는 속성을 가진 각도 응용 프로그램에서 비슷한 클래스를 정의하는 것입니다. 그런 다음 각도 클래스 객체 ' 회사 '로 객체를 수락 할 수 있습니다 와 .

예를 들어 아래의 프론트 엔드 코드를 참조하십시오. 더 명확해야하는 것이 있으면 의견으로 알려주십시오.

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

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

회사는 스프링 부트 앱의 엔티티 객체이며 Angular의 클래스이기도합니다.

export class Company {
    public id: number;
    public name: string;
    public owner: User;
    public locations: Array<Location>;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.