import { createTransformer, ITransformer } from "mobx-utils";
const undefinedObjectSymbol = Symbol("isUndefinedObject");
class UndefinedObject {
readonly [undefinedObjectSymbol]: true = true as const;
}
function isUndefinedObject(x: any): x is UndefinedObject {
return typeof x === "object" && undefinedObjectSymbol in x;
}
const undefinedObject = new UndefinedObject();
/**
* This function is identical to the MobX `createTransformer` function except that it allows `undefined` to be used as a transformed value.
* @param transformer The transformer function.
* @param onCleanup A function called when a memoized result is no longer needed.
*/
export default function createTransformerAllowUndefined(
transformer: ITransformer,
onCleanup?: (resultObject: B | undefined, sourceObject?: A) => void
): ITransformer {
function unwrap(object: A | UndefinedObject): B {
return transformer(isUndefinedObject(object) ? undefined : object);
}
Object.defineProperty(unwrap, "name", {
value: (transformer.name || "anonymous") + "-allowUndefined"
});
const unwrapOnCleanup =
onCleanup === undefined
? undefined
: function (
resultObject: B | undefined,
sourceObject?: A | UndefinedObject
): void {
const unwrapped = isUndefinedObject(sourceObject)
? undefined
: sourceObject;
return onCleanup(resultObject, unwrapped);
};
const transformed: ITransformer = createTransformer<
A | UndefinedObject,
B
>(unwrap, unwrapOnCleanup);
return function wrap(object: A | undefined): B {
return transformed(object === undefined ? undefinedObject : object);
};
}