npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

object-canonical-keys

v1.0.0

Published

Cache that always returns the same instance of array of keys

Downloads

177

Readme

objectCanonicalKeys building status

Object canonical keys is a replacement for Object.keys. The original Object.keys returns a new array for each invocation, regardless it is the same object, or it has the same keys. This behavior is okay in most of the situations, but when we are handling concepts as purity or as memoizers it becomes a problem.

If you look to the Redux documentation, inside recipes there is the recommendation of splitting the state as follows:

{
  entities: {
    byId: {
      id1: { ... },
      id2: { ... },
      ...
      idN: { ... },
    },
    allIds: ['id1', 'id2', ..., 'idN'],
  }
}

It is because ids usually do not change, but entities do. By keeping them apart in two lists, you can keep the same instance of the array of ids when you change your objects. It enables all sorts of optimizations and delivers dramatic improvements in React and other library performances.

However, there is a catch; you must write two logics for every kind of entity and action: one to manage entities, and other to manage the array of keys. That is not desirable, it adds extra complexity and breaks part of the Redux philosophy of having a normalized state and let memoization do the complex job of computing derived values efficiently.

objectCanonicalKeys borns with the desire to stop with this duplicity and keep high degrees of performance. Unlike Object.keys, objectCanonicalKeys ensures to return the same instance in each invocation with any object with the same keys.

Quick Use

Install with npm:

npm install --save object-canonical-keys

or yarn:

yarn add object-canonical-keys

And use in your Code:

import objectCanonicalKeys from 'object-canonical-keys'

const getEntitiesIds = (state) => objectCanonicalKeys(state.entities)

objectCanonicalKeys API

It is a replacement of Object.keys except that it does work with non-objects.

Given any object it returns an array with the keys like the one returned by Object.keys:

const keys = Object.keys({ name: 'alice', age: 7 })
const canonicalKeys = objectCanonicalKeys({ name: 'alice', age: 7 })

expect(canonicalKeys).toEqual(keys)

Given any array it returns an array with the keys like the one returned by Object.keys:

const keys = Object.keys([1, 2, 3])
const canonicalKeys = objectCanonicalKeys([1, 2, 3])

expect(canonicalKeys).toEqual(keys)

Unlike Object.keys, it returns the same array instance given the same object:

// objectCanonicalKeys
const object = { name: 'alice', age: 7 }
const canonicalKeys1 = objectCanonicalKeys(object)
const canonicalKeys2 = objectCanonicalKeys(object)

expect(canonicalKeys1).toBe(canonicalKeys2)

// Object.keys
const keys1 = Object.keys(object)
const keys2 = Object.keys(object)

expect(keys1).not.toBe(keys2)

Unlike Object.keys, it returns the same array instance if the object has the same keys:

// objectCanonicalKeys
const canonicalKeys1 = objectCanonicalKeys({ name: 'alice', age: 7 })
const canonicalKeys2 = objectCanonicalKeys({ name: 'alice', age: 7 })

expect(canonicalKeys1).toBe(canonicalKeys2)

// Object.keys
const keys1 = Object.keys({ name: 'alice', age: 7 })
const keys2 = Object.keys({ name: 'alice', age: 7 })

expect(keys1).not.toBe(keys2)

Unlike Object.keys, it throws an error when a non-object or array is used:

expect(() => objectCanonicalKeys('hello')).toThrow()

It throws an exception when a null value is used:

expect(() => objectCanonicalKeys(null)).toThrow()

See also

You may be also interested in a string cache to create memoizers:

  • StringCacheMap: a replacement for WeakMap when using strings instead of objects or arrays.