mlhaufe/brevity

Implement derived properties of Data variants

Closed this issue · 1 comments

const Person = Data({
  firstName: {},
  lastName: {},
  fullName: { value: (self) => `${self.firstName} ${self.lastName}` }
})

Since variants are readonly, this derived property should be treated as a lazily evaluated field.

Semantically like:

const obj = {
  get foo() {
    delete this.foo
    return this.foo = 'whatever'
  }
}

A challenge here is that the variant needs to be frozen while also enabling this lazy redefinition..

An approach might be to emulate frozen by returning a Proxy:

function createLazyObject(getter) {
  let isInitialized = false;
  let value;
  
  const proxy = new Proxy({}, {
    get(target, prop) {
      if (!isInitialized && prop === "computed") {
        value = getter();
        isInitialized = true;
        Object.defineProperty(proxy, "computed", {
          value,
          writable: false,
          configurable: false
        });
      }
      return Reflect.get(target, prop);
    },
    set(target, prop, value) {
      if (isInitialized)
        throw new TypeError("Cannot set property on a frozen object");
      return Reflect.set(target, prop, value);
    },
    deleteProperty(target, prop) {
      if (isInitialized)
        throw new TypeError("Cannot delete property on a frozen object");
      return Reflect.deleteProperty(target, prop);
    },
    defineProperty(target, prop, descriptor) {
      if (isInitialized)
        throw new TypeError("Cannot define property on a frozen object");
      return Reflect.defineProperty(target, prop, descriptor);
    }
  });

  return proxy;
}

This latter approach is pretty heavy to support the functionality