-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistency when comparing simple objects and class instances with getters and private JS fields #91
Comments
You and I start to have different definition of "simple". 🙂 Objects with getters that have impure results is pretty rare, hence why we (and have other comparators, including
I'm sorry I don't have much better to offer right now, but it is something of an intentional decision to target the primary use case for speed, which has a trade off of not handling edge cases like this. Hopefully in the future, though, I have a better answer. |
@planttheidea Yes, by simple I meant objects, that are not instances of any classes, but just plain javascript objects with getter properties 😄 I agree, it is definitely not easy to fix. I discovered this issue during debugging a test that should fail, but didn't. I was comparing An additional pitfall here was that the TypeScript interface just exposes the |
It looks to be more systemic than I thought; the reason the property is not discoverable (even with accessors like However, that is only from a generic usage. Specific use-cases can have specific solutions, and this is definitely a specific use-case! Since the properties in question are known (I'm assuming its the const circularDeepEqual = createCustomCircularEqual(({ areObjectsEqual }) => ({
areObjectsEqual: (a, b, isEqual, meta) => areObjectsEqual(a, b, isEqual, meta) && isEqual(a.data, b.data., meta);
})); This is spitballing a bit, but something like this should give you what you want for your specific use-case. It is highly specific to the contract, so you might want to guard a bit: const circularDeepEqual = createCustomCircularEqual(({ areObjectsEqual }) => ({
areObjectsEqual: (a, b, isEqual, meta) => {
if (!areObjectsEqual(a, b, isEqual, meta)) {
return false;
}
const aCloudEvent = a instanceof CloudEvent;
const bCloudEvent = b instanceof CloudEvent;
if (aCloudEvent || bCloudEvent) {
return aCloudEvent && bCloudEvent && isEqual(a.data, b.data, meta);
}
return true;
};
})); The contract for |
@planttheidea thank you for looking into this. My specific use case was fixed by removing the usage of private fields, but I guess there might be other cases coming where similar issues occur, when private fields are more widely in use. Thank you for proposing a solution 👍 |
I don't foresee a solution to this on the horizon, as this is related to aspects of the language which are difficult at minimum to work around. Therefore, I'm closing this issue. However, if in the future you find an example of a working implementation in the wild (example: |
In the follwing tests the first test fails and the second test succeeds:
Also see the following stackblitz: https://stackblitz.com/edit/node-hw8ssy?file=index.spec.ts
As a developer this behavior seems to be inconsistent and I would expect that the first test also considers those class instances to be inequal.
Note: I guess the following code is the cause of this issue:
fast-equals/src/objects.ts
Line 22 in 342d9a1
Both
for (const key in obj)
and generallyObject.keys(obj)
will enumerate the getter keys of simple objects, but not those of class instances.Also note:
jest
suffers of the same issue: jestjs/jest#13535The text was updated successfully, but these errors were encountered: