function createElement (type, { attrs = {}, children = [] }) {
if (Object.prototype.toString.call(arguments[1]) !== '[object Object]') {
throw Error('The options argument must be an object');
}
return {
type,
attrs,
children
}
}
I have a function which takes two arguments: a string and an object. In the function declaration, I am unpacking the object's values through destructuring.
When it comes to making sure the second argument is an object, I know I can do this check: Object.prototype.toString.call(arguments[1] !== 'object Object')
.
But if null
or undefined
are passed as arguments, this error occurs: Uncaught TypeError: Cannot destructure property 'attrs' of 'undefined' or 'null'.
. This is understandable because null
and undefined
cannot be coerced into objects. What can I do to guard against this?
If an array
, number
etc is passed as a second argument, no error is thrown because they can be coerced and I can then handle those values in the function body. When dealing with null
or undefined
, the code in the function is never executed.
// expected behaviour
createElement('div', []); // Uncaught Error: The options argument must be an object
createElement('div', function(){}); // Uncaught Error: The options argument must be an object
createElement('div', false); // Uncaught Error: The options argument must be an object
createElement('div', new Date()); // Uncaught Error: The options argument must be an object
createElement('div', 4); // Uncaught Error: The options argument must be an object
// unwanted behaviour
createElement('div', null); // Uncaught TypeError: Cannot destructure property `attrs` of 'undefined' or 'null'
createElement('div', undefined); // Uncaught TypeError: Cannot destructure property `attrs` of 'undefined' or 'null'
Edited to provide final solution: After reading the comments, it appears the only solution is either to allow the exception to be thrown or to destructure the code in the function body and handle the error. This is the solution I have chosen:
createElement (type, opts) {
if (arguments[1] !== undefined && Object.prototype.toString.call(opts) !== '[object Object]') {
throw Error('The options argument must be an object');
}
const { attrs = {}, children = [] } = opts || {};
return {
type,
attrs,
children
}
}
This function probably does what you want (allow a null
or undefined
second arg to be defaulted):
function createElement (type, obj) {
const arg1 = arguments[1];
if (arg1 !== null && arg1 !== undefined &&
Object.prototype.toString.call(arg1) !== '[object Object]') {
throw Error('The options argument must be an object');
}
let { attrs = {}, children = [] } = obj || {}
return {
type,
attrs,
children
}
}
This function also fixes your object test to work properly.
[UPDATED]
If you do want null
to also throw the non-object Error, you can use this:
function createElement (type, obj) {
const arg1 = arguments[1];
if (arg1 !== undefined &&
Object.prototype.toString.call(arg1) !== '[object Object]') {
throw Error('The options argument must be an object');
}
let { attrs = {}, children = [] } = obj || {}
return {
type,
attrs,
children
}
}