Yeah in general it’s good to avoid sometimes returning a value and sometimes undefined.
There’s an equivalence you can make between a type and a mathematical set, where you say that the type is the set of all possible values for that type.
In both JavaScript and math, multiplication of numbers is an operation that has a special property called closure, which means that the return type is the same as the input types. Multiply a number by another number and you will ALWAYS get a number back. The inputs and the outputs are in the same set, which means you can go nuts multiplying numbers and you’ll never have to check your values to make sure they’re still numbers; it can be safely assumed.
JavaScript gives NaN a type of “number” as a clever compromise. Instead of throwing an error when multiplying a number by a non-number, JS allows multiplication to still return a “number” (`4 * ‘a’ === NaN`) and then you don’t need to ever worry about accidentally “leaving” the set of numbers (`NaN * 10 === NaN`).
More likely than not though, multiplying a number and a string is just not a useful thing to do. With a good type system, a program that could wind up in a situation of multiplying a string and a number can be rejected by the compiler.
So in a roundabout answer to your question, a lot of “what then?!” situations can be entirely avoided with a good type system. For the remaining situations like accessing an element in an array that may not exist, a Maybe can make a lot of sense.
(Maybe Float turns out to be just like JavaScript’s numbers, but instead of NaN you have Nothing.)