Как сравнить два типизированных объекта (с интерфейсом) в React? - PullRequest
1 голос
/ 26 мая 2020

Необходимо получить дельту (ключ / значение) измененных атрибутов между двумя объектами. Код машинописный. Два объекта были созданы с помощью одного и того же интерфейса.

export interface ITestObj {
   att1: string;
   att2: string[];
   att3: string;
}

Я получаю сообщение об ошибке, что атрибут объекта нельзя использовать в качестве индекса. Не могу сделать что-то вроде этого:

if(objA['att1'] !== objB['att1']) {
}

Пытаясь исправить это, я попытался изменить интерфейс на:

export interface ITestObj {
       [att1: string]: string;
       att2: string[];
       att3: string;
    }

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

Как мне получить атрибуты, которые отличаются между objA и objB?

Большое спасибо.

Ответы [ 3 ]

0 голосов
/ 26 мая 2020

Вы можете попробовать

if(objA.att1 !== objB.att1) {
}

Но Лучше использовать

if(JSON.stringify(objA) !== JSON.stringify(objB)) {
}
0 голосов
/ 26 мая 2020

Я попытался дать разбивку нескольких решений в следующем коде:

type A = {
  att1: string;
  att2: string[];
  att3: string[];
};

const compare = <T extends {}>(a: T, b: T): boolean => {
  // Now there is several ways of doing this, all come with pros and cons

  // 1. If you are absolutely certain that the objects have ALL the attributes
  // from interface T (and no other attributes hidden from TypeScript)
  // you can just well use something like isEqual from lodash or similar
  // OR take the keys of one of your objects which will give you an array:
  //
  // const keys = ['att1', 'att2', 'att3']
  //
  // And you need to tell TypeScript that you are sure that these keys are exactly the ones from interface T
  // by casting the string[] (that you get from Object.keys) to K[]
  type K = keyof T;
  const keys = Object.keys(a) as K[];

  // Then finally loop over those keys and do the comparison that you want, I just sketched a thing here
  //
  // Note that to compare the string arrays you will need something more sophisticated than '==='!
  for (const key of keys) {
    if (a[key] !== b[key]) return false;
  }

  // 2. If you are not sure about what attributes there might be but the interfaces you need to compare
  // are always the same (i.e. you don't need compare() to be generic)
  //
  // In this case you can either store the keys you expect in a hard-coded array:
  type KA = keyof A;
  const hardcodedKeys: KA[] = ['att1', 'att2', 'att3'];

  // And again do your comparison here

  // You can also go fancy and use something like ts-transformer-keys:
  // https://www.npmjs.com/package/ts-transformer-keys
  // which will give you the list of keys for a small price of hooking up the TypeScript transform

  // And again do your comparison here

  return true;
};

Но даже с преобразованием вы не сможете сделать свою функцию generi c! Преобразование не знает, каким будет параметр типа T, потому что он зависит от того, где вызывается функция, поэтому вы не можете извлечь ее ключи!

Это связано с самим TypeScript, вы должны дать ему hand there:

// You will need to pass the array of keys to the function explicitly
// and let TypeScript just check that what you passed actually are keys of T
const compareProperties = <T extends {}>(a: T, b: T, keys: (keyof T)[]): boolean => {
  for (const key of keys) {
    if (a[key] !== b[key]) return false;
  }

  return true;
};

Опять же, вы можете использовать ts-transformer-keys, чтобы сгенерировать этот массив для вас во время компиляции.

0 голосов
/ 26 мая 2020

Вы можете использовать typeof() для сравнения типов значений:

if (typeof objA.att1 !== typeof objB.att1) {
    // ...
}

См. typeof type guards в документации TypeScript.

...