rustyBucketBay
rustyBucketBay

Reputation: 4561

Object equality comparison typescript. Cannot apply Object properties to generic type

Trying to obtain understand better object comparison in Javascript, along with the property access with typescript, I tried to make for my class an Equal comparer from this starting point.

TypeScript : Object Equality Comparison (Object Equals Object)

I know this can be done with stringify and loadash, but I find it interesting to dig into the object properties to apply logic.

This is the code to compare the two objects (from the link above):

private equals<T>(x: T, y: T): boolean {
    if (x === y) {
      return true; // if both x and y are null or undefined and exactly the same
    }
    if (!(x instanceof Object) || !(y instanceof Object)) {
      return false; // if they are not strictly equal, they both need to be Objects
    }
    if (x.constructor !== y.constructor) {
      // they must have the exact same prototype chain, the closest we can do is
      // test their constructor.
      return false;
    }
    for (const p in x) {
      if (!x.hasOwnProperty(p)) {
        continue; // other properties were tested using x.constructor === y.constructor
      }
      if (!y.hasOwnProperty(p)) {
        return false; // allows to compare x[ p ] and y[ p ] when set to undefined
      }
      if (x[p] === y[p]) {
        continue; // if they have the same strict value or identity then they are equal
      }
      if (typeof (x[p]) !== 'object') {
        return false; // Numbers, Strings, Functions, Booleans must be strictly equal
      }
      if (!this.equals(x[p], y[p])) {
        return false;
      }
    }
    for (const p in y) {
      if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) {
        return false;
      }
    }
    return true;
  }

My problem is that I cannot access the Object properties constructor and hasOwnProperty. I obtain the error:

Property 'hasOwnProperty' does not exist on type 'Vec3'.ts(2339).

I tried to implement the interface:

interface ObjectPropertiesHandlable {
  constructor: void;
  hasOwnProperty: void;
}

So that in the declaration private equals<T extends ObjectPropertiesHandlable>(x: T, y: T): boolean { I can fix the compilation error.

But if so, the arguments here won't fit:

    if (!this.equals(x[p], y[p])) {
        return false;
      }

As p is of type const p: Extract<keyof Vec3, string> (by the typescript intellisense onHover)

If I substitute the generic by my class type (it's a Vec3 class, however not relevant) although it has a constructor, I keep having the errors:

Property 'hasOwnProperty' does not exist on type 'Vec3'.ts(2339).

Property 'constructor' does not exist on type 'Vec3'.ts(2339).

If I apply an interface to avoid the object property error, I obtain this error:

enter image description here

Upvotes: 1

Views: 1453

Answers (1)

to make it work, try next code :

type Indexed = {
  [index: string]: unknown
}

const equals = <T extends Indexed>(x: T, y: T) => {
  // ... your code
}

You just should asure TS that your arguments are actually objects.

Please take a look on answer

UPDATE Try:

type Indexed = {
  [index: string]: Indexed
}

I ti a little bit dirty, but if you will explain me what are U trying to achieve maybe I will provide better solution

Upvotes: 2

Related Questions