Сопоставить универсальный массив с массивом классов TypeScript - PullRequest
0 голосов
/ 07 ноября 2019

У меня есть typescript класс:

export class Vehicle {
  constructor(
    id: string,
    makeId: string,
    makeName: string,
    modelName: string,
  ) {
    this.id = id;
    this.makeId = makeId;
    this.makeName = makeName;
    this.modelName = modelName;
  }

  public id: string;
  public makeId: string;
  public makeName: string;
  public modelName: string;
}

Далее у меня есть axios сообщение:

var results = await axios({
  method: "post",
  url: `${api}/api/vehicles`,
  responseType: "json",
  data: {
    searchTerm: searchTerm
  }
});

Это сообщение возвращает следующее json:

results: {
    data: {
        suggestions: [
            {
                data: {
                    id: "93dbae75-cf32-11e9-904a-88d7f67d5c52",
                    makeId: "8641d37e-cf1e-11e9-904a-88d7f67d5c52",
                    makeName: "Audi",
                    modelName: "TT RS Coupe"
                },
                value: "(2012) Audi - TT RS Coupe"
            },
            {
                data: {
                    id: "93dcc3f4-cf32-11e9-904a-88d7f67d5c52",
                    makeId: "8641d37e-cf1e-11e9-904a-88d7f67d5c52",
                    makeName: "Audi",
                    modelName: "TT RS Coupe"
                },
                value: "(2013) Audi - TT RS Coupe"
            },
            {
                data: {
                    id: "72c4afcb-cf32-11e9-904a-88d7f67d5c52",
                    makeId: "862fba2f-cf1e-11e9-904a-88d7f67d5c52",
                    makeName: "Acura",
                    modelName: "RSX"
                },
                value: "(2003) Acura - RSX"
            },
        ]
    }
}

Как мне отобразить этот json набор результатов в массив моего класса машинописи? Я пробовал следующее:

for(let result in results.data.suggestions) {
  vehicles.push(result.data:Vehicle);
}

Однако, он принимает result в let result в виде строки. Если я console.log результат, я получаю индекс массива.

1 Ответ

1 голос
/ 07 ноября 2019

Основная проблема в том, что вы используете for-in для циклического перебора элементов массива, а это не то, что делает for-in. См. ответы на этот вопрос для деталей, но вы, вероятно, хотите for-of. Кроме того, двоеточие не делает утверждение типа , для этого вы используете <Vehicle>result.data или result.data as Vehicle.

for (const {data} of results.data.suggestions) {
  vehicles.push(data as Vehicle); // Or you may need `data as unknown as Vehicle`
}

Отдельная проблема заключается в том, что если вы делаете то, чтоописанные объекты не будут экземплярами Vehicle, хотя они будут совместимы с точки зрения типизации утки. Это нормально на данный момент , но если вы когда-нибудь дадите Vehicle методов, у них их не будет.

У вас есть несколько вариантов решения этой проблемы:

  1. Создайте Vehicle interface вместо class.

  2. Сделайте так, чтобы конструктор Vehicle принимал Vehicle -подобный объект, а недискретные параметры (возможно, через деструктуризацию)

  3. Перегрузить конструктор Vehicle, чтобы принять Vehicle -подобный объект и заполнить экземпляр из него.

# 1 довольно очевидно:

interface Vehicle {
  id: string;
  makeId: string;
  makeName: string;
  modelName: string;
}

Тогда ваш цикл выглядит так:

for (const {data} of results.data.suggestions) {
  vehicles.push(data as Vehicle); // Or you may need `data as unknown as Vehicle`
}

# 2 выглядит примерно так:

interface VehicleLike {
  id: string;
  makeId: string;
  makeName: string;
  modelName: string;
}
export class Vehicle {
  // *** Note the { and } in the parameter list
  constructor({
    id,
    makeId,
    makeName,
    modelName
  }: VehicleLike) {
    this.id = id;
    this.makeId = makeId;
    this.makeName = makeName;
    this.modelName = modelName;
  }

  public id: string;
  public makeId: string;
  public makeName: string;
  public modelName: string;
}

Тогда

for (const {data} of results.data.suggestions) {
  vehicles.push(data as VehicleLike); // Or you may need `data as unknown as VehicleLike`
}

# 3 выглядит примерно так:

interface VehicleLike {
  id: string;
  makeId: string;
  makeName: string;
  modelName: string;
}
export class Vehicle {
  constructor(vehicle: VehicleLike);
  constructor(
    id: string,
    makeId: string,
    makeName: string,
    modelName: string,
  );
  constructor(
    x: string|VehicleLike,
    makeId?: string,
    makeName?: string,
    modelName?: string,
  ) {
    if (typeof x === "string") {
        this.id = x;
        this.makeId = makeId as string;
        this.makeName = makeName as string;
        this.modelName = modelName as string;
    } else {
        this.id = x.id;
        this.makeId = x.makeId;
        this.makeName = x.makeName;
        this.modelName = x.modelName;
    }
  }

  public id: string;
  public makeId: string;
  public makeName: string;
  public modelName: string;
}

Затем (снова)

for (const {data} of results.data.suggestions) {
  vehicles.push(data as VehicleLike); // Or you may need `data as unknown as VehicleLike`
}

Примечание: Если вы не изменяете Vehicle в соответствии с любым из вышеперечисленных и сохраняете его так, как он есть, и , если вы хотите , это функционально идентично вашему текущему Vehicle, только снамного меньше повторений:

export class Vehicle {
  constructor(
   public id: string,
   public makeId: string,
   public makeName: string,
   public modelName: string,
  ) {
  }
}

Это удобная функция, предоставляемая TypeScript.

...