Приведение JSON к сложным типам - PullRequest
0 голосов
/ 08 января 2019

Я пытаюсь привести мой http.get ответ к реальному объекту -> в моем конкретном случае массив сложных объектов.

В обычном сценарии, когда вам не нужно какое-либо конкретное приведение, вы можете сделать следующее (упрощенно):

return this.httpClient.get(api, this._options_get)
  .pipe(
    map((response: any) => {
      return response.value as NewProduct[];
    })
  );

Поскольку мне нужно на самом деле привести это к объекту, я создал этот статический метод, который делает это:

static toProduct(otherProduct: any): NewProduct {
    let item = new NewProduct();

    Object.keys(otherProduct).forEach(prop => {
        if (typeof otherProduct[prop] === "object" && otherProduct[prop]) {
            if (!item.hasOwnProperty(prop))
                item[prop] = otherProduct[prop];
            Object.assign(item[prop], otherProduct[prop]);
        }
        else
            item[prop] = otherProduct[prop];
    })

    return item;
}

Под Object.assign Я беру уже существующий объект, который был инициализирован в первой строке, и я просто копирую все свойства из otherProduct в него. Однако я начинаю сталкиваться с проблемой, когда дело доходит до массива объектов. Пример (с упрощенным классом):

export class Person {
    name:string;
    age:number;
    addresses:Address[] = [];
}
export class Address {
    street:string;
    city:string;
    fullAddress() : string { return this.street + this.city; }
}

Как только я получу такой массив, у меня не будет никакого начального объекта в item. Это означает, что не существует начального конструктора класса, который приводит к простому Object. Это не ошибка для JavaScript или TypeScript; однако, когда я пытаюсь получить доступ к внутреннему методу класса (в нашем упрощенном случае fullAddress(), я не смогу.

Причина, по которой мне это нужно, заключается в том, что я переопределяю метод toString() в своих подклассах, что необходимо для MatTableDataSource при использовании метода filter (который работает со строками).

Есть ли способ получить элементы из http.get() и правильно сопоставить результаты с типизированными объектами?

1 Ответ

0 голосов
/ 08 января 2019

Ты слишком универсален. Вы создаете объекты объектов, а не объекты Product с потомками адресов.

Если вы хотите создать новый продукт, вам нужно понять связь между результатами API и данными, которые вы хотите в пользовательском интерфейсе.

Поскольку вы используете классы, а не интерфейсы и хотите наследовать функции, единственный способ получить новые адреса в новом объекте - это ключевое слово new.

И вам придется пройти через. Вы не найдете ярлык для этого. Вам нужно будет перебрать данные и преобразовать их. Если ваш API дает вам ApiPerson, тогда вы захотите сделать что-то вроде этого:

const addresses = apiPerson.addresses.map((apiAddress) => {
    const address = new Address();
    // map properties of apiAddress to address...
    return address;
});

Теперь, когда у вас есть addresses, вы можете сопоставить apiPerson со свойствами new Person() и затем установить newPerson.addresses = address.

...