Как сравнить два типизированных объекта (с интерфейсом) в React?

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

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?

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


person user636312    schedule 26.05.2020    source источник
comment
Можете ли вы поделиться еще немного кода, чтобы помочь нам выполнить код и решить проблему?   -  person SorcererApprentice    schedule 26.05.2020
comment
у меня ни одной ошибки. Я игнорирую третий фрагмент.   -  person SorcererApprentice    schedule 26.05.2020


Ответы (3)


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

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

См. раздел защиты типов в документации по TypeScript. .

person Andrew Hill    schedule 26.05.2020

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

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

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

if(JSON.stringify(objA) !== JSON.stringify(objB)) {
}
person DevLoverUmar    schedule 26.05.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;
};

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

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

// 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 для создания этого массива во время компиляции.

person Ján Jakub Naništa    schedule 26.05.2020