packages/shared/util/Recoil_lazyProxy.js (25 lines of code) (raw):

/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @emails oncall+recoil * @flow strict-local * @format */ 'use strict'; /** * Return a proxy object based on the provided base and factories objects. * The proxy will include all properties of the base object as-is. * The factories object contains callbacks to obtain the values of the properies * for its keys. * * This is useful for providing users an object where some properties may be * lazily computed only on first access. */ // $FlowIssue[unclear-type] function lazyProxy<Base: {[string]: any}, Factories: {[string]: () => any}>( base: Base, factories: Factories, ): { ...Base, ...$ObjMap<Factories, <F>(() => F) => F>, } { const proxy = new Proxy(base, { // Compute and cache lazy property if not already done. get: (target, prop) => { if (!(prop in target) && prop in factories) { target[prop] = factories[prop](); } return target[prop]; }, // This method allows user to iterate keys as normal ownKeys: target => { // Materialize all lazy properties. This appears to be necessary for // onKeys to work properly, the object must actually have the properties // that it reports to have. for (const lazyProp in factories) { // Call this for side-effect to materialize lazy property // $FlowExpectedError[prop-missing] proxy[lazyProp]; } return Object.keys(target); }, }); // $FlowIssue[incompatible-return] return proxy; } module.exports = lazyProxy;