mirror of
https://github.com/pmndrs/zustand.git
synced 2025-12-08 19:45:52 +00:00
feat(vanilla): update shallow compare function and tests (#3108)
* feat(vanilla): update shallow compare function and tests * prefer Object.getPrototypeOf * docs: update shallow docs * feat: minor fixes --------- Co-authored-by: daishi <daishi@axlight.com> Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
This commit is contained in:
parent
37878da019
commit
a56a3e4bde
@ -25,6 +25,7 @@ const equal = shallow(a, b)
|
||||
- [Comparing Maps](#comparing-maps)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Comparing objects returns `false` even if they are identical.](#comparing-objects-returns-false-even-if-they-are-identical)
|
||||
- [Comparing objects with different prototypes](#comparing-objects-with-different-prototypes)
|
||||
|
||||
## Types
|
||||
|
||||
@ -224,3 +225,24 @@ In this modified example, `objectLeft` and `objectRight` have the same top-level
|
||||
primitive values. Since `shallow` function only compares the top-level properties, it will return
|
||||
`true` because the primitive values (`firstName`, `lastName`, and `age`) are identical in both
|
||||
objects.
|
||||
|
||||
### Comparing objects with different prototypes
|
||||
|
||||
The `shallow` function checks whether the two objects have the same prototype. If their prototypes
|
||||
are referentially different, shallow will return `false`. This comparison is done using:
|
||||
|
||||
```ts
|
||||
Object.getPrototypeOf(a) === Object.getPrototypeOf(b)
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Objects created with the object initializer (`{}`) or with `new Object()` inherit from
|
||||
> `Object.prototype` by default. However, objects created with `Object.create(proto)` inherit from
|
||||
> the proto you pass in—which may not be `Object.prototype.`
|
||||
|
||||
```ts
|
||||
const a = Object.create({}) // -> prototype is `{}`
|
||||
const b = {} // -> prototype is `Object.prototype`
|
||||
|
||||
shallow(a, b) // -> false
|
||||
```
|
||||
|
||||
@ -57,14 +57,18 @@ export function shallow<T>(valueA: T, valueB: T): boolean {
|
||||
) {
|
||||
return false
|
||||
}
|
||||
if (!isIterable(valueA) || !isIterable(valueB)) {
|
||||
return compareEntries(
|
||||
{ entries: () => Object.entries(valueA) },
|
||||
{ entries: () => Object.entries(valueB) },
|
||||
)
|
||||
if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) {
|
||||
return false
|
||||
}
|
||||
if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {
|
||||
return compareEntries(valueA, valueB)
|
||||
if (isIterable(valueA) && isIterable(valueB)) {
|
||||
if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {
|
||||
return compareEntries(valueA, valueB)
|
||||
}
|
||||
return compareIterables(valueA, valueB)
|
||||
}
|
||||
return compareIterables(valueA, valueB)
|
||||
// assume plain objects
|
||||
return compareEntries(
|
||||
{ entries: () => Object.entries(valueA) },
|
||||
{ entries: () => Object.entries(valueB) },
|
||||
)
|
||||
}
|
||||
|
||||
@ -172,6 +172,25 @@ describe('shallow', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('mixed cases', () => {
|
||||
const obj = { 0: 'foo', 1: 'bar' }
|
||||
const arr = ['foo', 'bar']
|
||||
const set = new Set(['foo', 'bar'])
|
||||
const map = new Map([
|
||||
[0, 'foo'],
|
||||
[1, 'bar'],
|
||||
])
|
||||
|
||||
it('compares different data structures', () => {
|
||||
expect(shallow<unknown>(obj, arr)).toBe(false)
|
||||
expect(shallow<unknown>(obj, set)).toBe(false)
|
||||
expect(shallow<unknown>(obj, map)).toBe(false)
|
||||
expect(shallow<unknown>(arr, set)).toBe(false)
|
||||
expect(shallow<unknown>(arr, map)).toBe(false)
|
||||
expect(shallow<unknown>(set, map)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('generators', () => {
|
||||
it('pure iterable', () => {
|
||||
function* gen() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user