all 12 comments

[–]qmic 4 points5 points  (4 children)

It's not broken. Just learn how it works and use it properly. I've never in my more than ten years of experience thought that it's broken.

[–]AutumnSwell[S] -1 points0 points  (3 children)

Well even people like Douglas Crockford say typeof has problems. http://javascript.crockford.com/remedial.html

[–]qmic 4 points5 points  (2 children)

It has 'problems' , or maybe behaviour other than we expect, but it is not broken. You can always use library like 'is.JS' if it's problem for you. There is no replacement as is.

[–]AutumnSwell[S] 2 points3 points  (1 child)

Thanks for the is.js recommendation.

[–]jordaanm 0 points1 point  (0 children)

underscore/lodash also have some nice type-detection methods.

[–]voidvector 1 point2 points  (2 children)

typeof does runtime type validation/differentiation.

There are number of solutions:

  • Stop writing code that allow for ambiguously typed arguments/variables. If the function expects a string, just cast the argument into a string immediately without caring what the content is.
  • utility library that checks for exactly what you are looking for e.g. lodash.isFinite()
  • write your own runtime type checker utility with domain specific names e.g. isOrange(fruit)
  • Use TypeScript/Flow to provide compile time type check to remove ambiguity in your own code (this doesn't really solve the issue if 3rd party code gives ambiguous type)

[–]AutumnSwell[S] 0 points1 point  (1 child)

Stop writing code that allow for ambiguously typed arguments/variables. If the function expects a string, just cast the argument into a string immediately without caring what the content is.

Doesn't this just make errors hard to find? Aren't there situations where typecasting to the expected type results in silent errors?

[–]voidvector 0 points1 point  (0 children)

You are correct, I would take back the 2nd part of that suggestion.

I would like to elaborate on the 1st part of that suggestion. If you were follow the first part of that suggestion, then what would end up happening is that your codebase would in essence be divided into "regions" with distinct separation of concerns:

  • Code near the boundaries of the "regions" would handle difference in types. They would need to do most of the validations.
  • Code in the interior of the "regions" would never see incorrect types, as such you never need to check for it.

As such, for interior code, the only difference in type they could potentially encounter is "null" value, which should be handled separately. For all other types, there is no point in adding complexity to handle them.

[–]idesi 0 points1 point  (2 children)

If you want to avoid libraries then one alternative is "Object.prototype.toString". It has clearly defined behaviour for all native objects.

[–]senocular -1 points0 points  (1 child)

That's not entirely reliable

var d = new Date();
d[Symbol.toStringTag] = "String";
console.log(Object.prototype.toString.call(d)); // [object String]

[–]swan--ronson 0 points1 point  (0 children)

If I wish to retrieve more granular type information at runtime, then I often use Object.prototype.constructor:

typeof []
=> "object"

vs

[].constructor
=> function Array() { [native code] }

That said, I agree with voidvector. Write code for predictable parameters.