So it just canonicalizes everything that is not a number into NaN.
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
People accustomed to strongly typed languages and thinking mostly of monolithic apps always pin things on dynamic typing even where it's not the cause. It's not about dynamic typing in this case.
What's going on here is partially because of separate compilation and partially because of mobile code (as Lars Bak explains[1]). Even if developing in a strongly typed language, the machinery would still have to take care to deal with the same thing. In fact, this isn't even JS; this file is TypeScript—and this expression being strongly typed is almost certainly exactly why this code was written this way: because `useControlledState<number>` demands it. If `useControlledState` were just vanilla JS and no one were doing typechecking during development and build, there would have been no problem with passing something else as an argument, because it will of course evaluate to NaN anyway when undergoing the number treatment.
(This is kind of subtle, but it's not that subtle. Too many people make this mistake, and there's probably something that needs to be done about that; "because dynamic languages" has become something of a thought-terminating cliché that leads people to the wrong conclusions—as demonstrated even in the interview, at the point where Bak felt prompted to point this out.)
1. Inside V8 — A Javascript Virtual Machine. Going Deep: Expert to Expert. Accessed July 3, 2020. <https://channel9.msdn.com/Shows/Going+Deep/Expert-to-Expert-...>.
My theory, by the way, was that the expression is normalizing the possible NaN representations to a definite one, possibly to prevent transporting information via the NaN representation.
Such “what the …?” code should have a comment explaining the intent (e.g. “replace non-numeric values by NaN”). If it is used in multiple places, that’s a good opportunity to define a function for it, so the intent only needs to be documented in a single place. (In programming languages with annotations as a language construct, annotations could alternatively also be used for referencing the documentation of a coding pattern from multiple places.)
Anyway, if they’re trying to coerce non-numbers into NaN, I’d write it like this:
typeof defaultValue === “number” ? defaultValue : NaN
I think that’s much more clear about the intent. I wouldn’t be confused by that code like I was confused by the code cited in the article.I'm not even sure that covering type conversions was intended here.
I'd much rather call this "normalizeNaN" or something.
I can sympathize with the argument of the OP, but I wouldn't exaggerate its profundity either. The intent was opaque enough for the OP that he got it completely wrong, and even under the OP's assumptions, the intent was still more opaque than necessary. Furthermore, you're still passing around `NaN`, which is sort of an analogue of passing around `null`. This example suggests that perhaps a better language construct ought to be used, like the `Option` type.
Written as is, the original code looks surprising. I've seen this kind of easily simplifiable multiple times in large codebases, after years of refactoring and automated transformations.
This culture should be encouraged more to make other developer's life easier, The thing I do nowadays is that I would often switch perspectives now and then, When switching perspectives, if i become confused, i would work on making the code more meaningful.
Even if we are doing a solo project, if we come back to the code after a long while, the code should be greeting us with wide open hands rather than looking like an unexplored jungle.
We should be building these semantics directly into our languages, not relying on programmers to strictly follow a "best practice". In this case, it would be making values non-nullable and baking in Result/Option/etc style types that force programmers into handling the null (or NaN) case.