уроки Как сделать объект JSON классом типов




создать json (13)

Если вы используете 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 с удаленного сервера REST. Этот объект JSON обладает всеми свойствами класса типов (по дизайну). Как передать полученный JSON-объект в var?

Я не хочу заполнять varcript типа (т. Е. Иметь конструктор, который принимает этот объект JSON). Он большой и копирует все по субобъекту по предмету и свойству по собственности займет много времени.

Обновление: вы можете, однако, передать его в интерфейс машинописного текста!


У меня была такая же проблема, и я нашел библиотеку, которая выполняет эту работу: https://github.com/pleerock/class-transformer .

Он работает следующим образом:

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

Он поддерживает вложенные дочерние элементы, но вам нужно украсить член вашего класса.


Я создал простой инструмент для этого beshanoe.github.io/json2ts В отличие от json2ts.com, он работает непосредственно в браузере и не отправляет ваши данные на неизвестные серверы. Также он имеет несколько настроек. Я буду работать над улучшением его функциональности


Я не вижу упоминания json-typescript-mapper: https://www.npmjs.com/package/json-typescript-mapper . Насколько я могу судить, это комбинация поиска Филипа Минглинчи и ответа Пака.


Я нашел очень интересную статью о родовом литье JSON для класса TypScript:

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, поскольку он может ненадлежащим образом помещать ваш экземпляр класса нерелевантными свойствами (а также определенными закрытиями), которые не были объявлены внутри самого класса.

В классе, который вы пытаетесь десериализовать, я бы гарантировал, что будут определены любые свойства, которые вы хотите десериализовать (нуль, пустой массив и т. Д.). Определив свои свойства с помощью начальных значений, вы обнаружите их видимость при попытке итерации членов класса для назначения значений (см. Метод десериализации ниже).

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

В приведенном выше примере я просто создал метод десериализации. В реальном мире я бы централизовал его в многоразовом базовом классе или методе обслуживания.

Вот как использовать это в чем-то вроде 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, так и список задач в соответствующие экземпляры классов.


Вы не можете просто передать результат обычного старого JavaScript из запроса Ajax в прототипный экземпляр класса JavaScript / TypeScript. Существует множество методов для этого и, как правило, связаны с копированием данных. Если вы не создадите экземпляр класса, он не будет иметь никаких методов или свойств. Он останется простым объектом JavaScript.

Хотя, если вы только имели дело с данными, вы могли бы просто сделать трансляцию в интерфейс (поскольку это чисто структура времени компиляции), для этого потребуется, чтобы вы использовали класс TypeScript, который использует экземпляр данных и выполняет операции с этими данными.

Некоторые примеры копирования данных:

  1. Копирование объекта AJAX JSON в существующий объект
  2. Разбирать строку JSON в специальный прототип объекта в JavaScript

В сущности, вы просто:

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

В TypeScript вы можете сделать утверждение типа с использованием интерфейса и дженериков:

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

Где ILocationMap описывает форму ваших данных. Преимущество этого метода заключается в том, что ваш JSON может содержать больше свойств, но форма удовлетворяет условиям интерфейса.

Надеюсь, это поможет!


В моем случае это работает. Я использовал функции Object.assign (target, sources ...) . Во-первых, создание правильного объекта, а затем копирует данные из объекта json в target.Example:

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

Хотя это не кастинг за слово; Я нашел 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"

Пока еще нет возможности автоматически проверять, имеет ли объект JSON, который вы получили с сервера, для свойств интерфейса машинописного машиностроения (считайте совместимым с). Но вы можете использовать User-Defined Type Guard

Учитывая следующий интерфейс и глупый json-объект (он мог быть любого типа):

interface MyInterface {
    key: string;
 }

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

Три возможных способа:

A. Тип Утверждение или простой статический литой, помещенный после переменной

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, цель которого примерно такая же, либо этот генератор функции проверки типа времени выполнения


Предполагая, что json обладает теми же свойствами, что и ваш класс типов, вам не нужно копировать свои свойства Json в свой тип машинописного текста. Вам просто нужно будет создать свой объект «Виджет», передавая json-данные в конструкторе.

В вашем обратном вызове ajax вы получаете компанию:

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

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

Для того, чтобы сделать эту работу:

1) Добавьте конструктор в свой класс Typcript, который принимает данные json в качестве параметра. В этом конструкторе вы расширяете свой json-объект с помощью jQuery, например: $.extend( this, jsonData) . $ .extend позволяет сохранять прототипы javascript при добавлении свойств объекта json.

2) Обратите внимание, что вам придется делать то же самое для связанных объектов. В случае Employees в этом примере вы также создаете конструктор, который принимает часть данных json для сотрудников. Вы вызываете $ .map для перевода сотрудников json на машинописные объекты Employee.

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

Это лучшее решение, которое я нашел при работе с классами Postscript и json-объектами.


Я использовал эту библиотеку здесь: 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));
}

Иногда вам придется разбирать значения JSON для plainToClass, чтобы понять, что это форматированные данные JSON





typescript