TypeError: undefined is not an object – React
In React (and other JavaScript-based languages and frameworks) a common error that you may come across during development is:
TypeError: undefined is not an object (evaluating '...')
This can be completely frustrating but the solution is usually fairly simply once you know where to start looking.
The Cause
Simply, you’re treating a variable like it is an object when it is not. ‘undefined’ means that your variable hasn’t yet been defined (in this case, our object has either not been instantiated or it has been but not assigned to the variable that you are using.
Object properties are accessed using the dot notation. For example, if I have an object called car with a property of model to access it in the code I would use:
car.model
If I set model to ‘A3’ and instantiate the car object successfully, assigning it to the variable car then this call would return ‘A3’. Something like:
let car = car('A3');
model = car.model;
However, lets say that I declare car but forget to instantiate it:
let car;
model = car.model;
‘car’ now exists – ‘undefined’ and subsequently when the second line runs, car is attempted to be accessed (whilst still undefined) so when it gets to the ‘.model’ part it will throw our error:
TypeError: undefined is not an object (evaluating 'car.model')
This is telling us that the (proposed) object car is actually undefined and therefore cannot be accessed like an object using dot notation. This is a simple example to illustrate the point – however often it isn’t necessarily us forgetting to instantiate an object but rather us storing an object in a variable that has been generated – for example:
try{
...
}catch(error){
let previousCaller = error.previousCaller
console.error(error.previousCaller.name)
}
In this example, we’ve extended the standard error object to include a previousCaller object. However, if there wasn’t a prior call, or this wasn’t set properly in our custom error object the the ‘console.error’ line will fall over. It will assign successfully to our previousCaller variable but it has in essence assigned nothing – or ‘undefined’.
The Fix
Firstly, if the object should always be populated, check that you have actually assigned the right object to your variable – or that indeed you have attempted to assign the object to the variable in the first place. This is one of the most common errors.
Secondly, you can step through your code in the developer tools console (using appropriate breakpoints before the assignment of the variable) to check the value of the variable at each stage. Is it being cleared unintentionally? Is it being overwritten? Is it being passed the parameters expected in the first place?
And finally…
Defensive Coding
Assume everything will fall over. Even if an object ‘should’ always be there – protect yourself. It’s a little extra code but can help you go a long way to making a much more robust solution.
Using our example above, we could only try to access the object after we’ve checked that it isn’t undefined using a simple conditional statement:
try{
...
}catch(error){
let previousCaller = error.previousCaller
if(!typeOf(error.previousCaller) == 'undefined')
//this will now only run if error.previousCaller is defined
console.error(error.previousCaller.name)
{
}
And hey presto! Your error has disappeared. You could improve it further still by adding an additional ‘else’ statement to the if to log if previousCaller is undefined – if it is something your expecting. If previousCaller being undefined is a valid scenario, then you can just leave it at the code above – there’s no point clogging logs with unnecessary information! If it should always be defined, you can use something like this:
if(!typeOf(error.previousCaller) == 'undefined'){
//this will now only run if error.previousCaller is defined
console.error(error.previousCaller.name)
}else{
//previousCaller is undefined - log away for analysis
console.error('previousCaller in function x is undefined at line x')
}
Defensive coding is often overlooked, particularly in commercial settings where time is at a premium and project deadlines are looming, but although it takes some time to implement in the beginning and learn how to do it pays (massive!) dividends in the long room and will usually reduce the overall development time of any project.
Hope that helps! Let us know in the comments below!