Rich keys

Value Symbols

I have some information, say a timestamp:

const t = Date.now();
// 1635817108916

It would be useful to be able to use this as a key. Here is one approach.

const object = { type: 'instant', time: Date.now() };
const symbol = Symbol(JSON.stringify(object));
const symbolValue = Object.freeze(Object.assign(Object(symbol), object));

I can now use this symbol object as an object key:

const cache = {
  [symbolValue]: {
    '/user': { name: "Jane Jones" }
  }
};
// {
//  [Symbol({"type":"instant","time":1635817108916})]: { '/user': { name: 'Jane Jones' } }
// }

I can read information from it:

symbolValue.type
// "instant"

symbolValue.time
// 1635817108916

It’s incredibly flexible yet self contained.

The JSON version of the object is its canonical string form.

function jsonSymbol(object) {
  Object.freeze(object);
  const symbol = Symbol.for(JSON.stringify(object));
  return Object.freeze(Object.defineProperties(Object(symbol), Object.getOwnPropertyDescriptors(object)));
}

function serialize(symbol) {
  return symbol.description;
}

function toObject(symbol) {
  return JSON.parse(symbol.description);
}

function urlSymbol(url) {
  const symbol = Symbol.for(url.href);
  return Object.freeze(Object.assign(Object(symbol), { href: url.href, host: url.host, pathname: url.pathname, search: url.search, hash: url.hash }));
}
const now = jsonSymbol({ type: 'instant', time: Date.now() });
now.time
// 1635817108916

const keyPath = jsonSymbol(['user', 123456]);
keyPath[1]
// 123456

const apiSymbol = urlSymbol(new URL("https://myapi.com/user"));
// '/user'

URLs

I have a URL to a resource, say to an API:

const apiURL = new URL("https://myapi.com")
const getUser = new URL("/user", apiURL);
// URL { href: 'https://myapi.com/user', … }

It would be useful to be able to use this as a key, and I can:

const cache = {
  [getUser]: { name: "Jane Jones" }
};
// {
//  'https://myapi.com/user': { name: 'Jane Jones' }
// }
cache[getUser]
// { name: 'Jane Jones' }

The canonical string of a URL is its href.


Canonical form

It would be useful to be able to get the canonical form of these values. This way we have a key that we can cache with.

function serialize(object) {
  if (typeof object === 'symbol') {
    return object.description;
  } else if (object instanceof URL) {
    return URL.toString();
  } else {
    throw new Error("Unsupported object");
  }
}

function deserialize(string) {
  if (string.startsWith("https:")) {
    return new URL(string);
  } else {
    return Symbol.for(JSON.parse(string));
  }
}