Skip to content

Instantly share code, notes, and snippets.

@monkeymonk
Last active March 16, 2022 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monkeymonk/a0a0eef371db989a09340522cc99a30e to your computer and use it in GitHub Desktop.
Save monkeymonk/a0a0eef371db989a09340522cc99a30e to your computer and use it in GitHub Desktop.
JavaScript optional function helper
/**
* Copy properties from source to target.
* @param target
* @param source
*/
function copyProps(target, source) {
const properties = Object.getOwnPropertyNames(source);
properties
.concat(Object.getOwnPropertySymbols(source))
.filter((key) => !key.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
.forEach((key) => {
const props = Object.getOwnPropertyDescriptor(source, key);
Object.defineProperty(target, key, props);
});
return target;
}
/**
* The optional function accepts any argument and allows you to access properties or call methods on that object.
* If the given object is null, properties and methods will return null instead of causing an error.
*
* @example
* const source = { bar: 'bar' };
* optional(source).foo; // return null
* optional(source, 'baz').foo; // return 'baz'
* optional(source, null, true).foo(); // return null
* optional(source, 'baz', true).foo(); // return 'baz'
* optional(source, (src) => src.bar).foo; // return 'bar'
* optional(source, (src) => src.bar, true).foo(); // return 'bar'
*
* @param source
* @param callback
* @param defaultValue
* @return {(function(): null)|{value}|null|*}
*/
function optional(source, defaultValue = null, callback = null) {
const result = copyProps({}, source);
return new Proxy(result, {
get(target, prop) {
if (target[prop] === undefined) {
if (callback === true) {
if (typeof defaultValue === 'function') {
return () => defaultValue(source);
}
return () => defaultValue;
} else if (typeof defaultValue === 'function') {
return defaultValue(source);
}
return defaultValue;
}
return target[prop];
},
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment