4 ms·
Type Checking in JavaScript
- slig 13y agoWho would've thought that after years of cursing them for spamming me, I would read something interesting on their tech blog.
- joshguthrie 13y agoThanks for summing up my thoughts.
- jtfairbank 13y agoSounds great! Looks like you can find similar functionality in underscore.js, although they ask you to do the checking explicitly, ie `isBoolean(true)`.
- stevecooperorg 13y agoGreat solution -- by the end, that final 'type' object starts to look good; type.isNumber(4); // true And it'd be easy to add validation versions, too, which might help clarify the types as one call per parameter; type.ensureIsNumber(myParameter); // throws exception if not a number which might help your code fail faster.
- marijn 13y agoWell, let's see var mostRecent = ''; if (type(c.messages) === 'array' || type(c.messages[0]) === 'object' || type(c.messages[0].text) === 'string') { mostRecent = c.messages[0].text.substring(0, 30); } return name + ': ' + mostRecent; .. apart from the fact that he probably meant && instead of || in that condition, we've also now got a system that silently swallows errors. Bugs can lurk in it without any more symptoms than producing empty strings where more interesting strings were expected. I much prefer my systems to crash when a programmer made an error, and do so noisily and detectably, so that the problem can be fixed. I also prefer the actual logic of my code to make up more than 20% of the lines. If you're going to add boilerplate type checks all over, the signal-to-noise ratio gets really bad. So don't do this. Use Typescript if you want to check types.
- annnnd 13y agoAgree with you 100%. One could use this system for asserts though: assert(type.isObject({}))); assert(type.isNumber(NaN)); // fails assert(type.isElement(document.createElement('div'))); assert(type.isRegExp(/abc/); This could increase readability (because it documents the data type expectations) and would also break on some errors as soon as possible.
- ghiculescu 13y agoIt's still a lot of code being run without real benefit. Use Typescript if you really want static types, write sufficient unit tests either way, and you don't need this.
- rimo 13y agoStatic types and unit tests don't solve or catch all problems. I'm thinking about event-driven messaging systems, which is pretty common in js; Static typing will not be of any help in that situation.
- embwbam 13y agoYou can use a different observer pattern sometimes that can be caught by static typing, like Signals
- danbruc 13y agoSufficiently advanced type systems can enforce an enormous range of constraints. You can for example create a type for trees enforcing that the tree must be balanced; code that would unbalance a tree will just not compile.
- annnnd 13y agoSure - and you can test types in your unit tests using the OP's technique. :)
- jonbretman 13y ago
- kashif 13y agoAlways been interested in things like these. Did something similar with python decorators, just for fun - https://github.com/kashifrazzaqui/pyutils https://github.com/kashifrazzaqui/pyutils
- ankurdhama 13y agoBasically adding "compiler bits" into your dynamically typed language application code.
- CmonDev 13y agoFixing the symptom.
- hbbio 13y agoTypechecking JavaScript is feasible. But will be really hard in practice. We have worked for years on the Opa technology, cf. http://opalang.org http://opalang.org. Opa is a typechecked language with a JS syntax that compiles to JavaScript. Unlike JS though, the semantics of the language borrows to functional programming languages, to ensure the type system is sound and type checking feasible with almost full type inference. Opa does more than type-checking to JS, but even if you just want to typecheck JS, basically you should look to design and implement a new programming language, with a syntax as close as possible to JS but with proper semantics and then that compiles to JS after type-checking. You could add a set of tools to help port actual JS code to this new language.
- k__ 13y agoWhat's with the obsession about (static) typing? I have written code in untyped languages all my life and it has never been a problem for me. The only problem I see with bigger JavaScript apps is the callback-hell. Funny thing is, most to-JavaScript languages focus on the type aspect. If I could write linear asynchronous code everything would be much more readable after coming back to some code a few months later.
- joe_fishfish 13y agoAgreed. Dynamic typing is fine once you get used to it, but the only thing I've found to solve the callback hell is a publish / subscribe architecture, which brings its own problems.
- eru 13y agoI've started with (bad) static typing in C, Pascal and friends, then got to use the dynamic Lisp and Python. But now I'm at (good) static typing again with Haskell (and OCaml). Good static typing saves you about half the units tests. And you don't even have to worry too much about that `half' being correct, because the type machinery in your compiler has been checked by thousands of people before. Whereas your tests are normally written from scratch. Types also make your testing life much easier. QuickCheck is about the gold standard in rules based testing, and QuickCheck in a type-inferred language is just so much less verbose than when you have to either manually add all type annotiations or have to go without types. (That's mostly because Haskell allows overloading by return type.)
- Bahamut 13y agoPromises & named functions are your friends! So you can do stuff like this: callToRemoteApi().then(processData) .then(makeAnotherCallToAnotherApi) .then(processAllTheData)
- camus2 13y agoYou still need to write functions ,that's the issue. => functions will make things a bit better,but await and generator syntax are the key to solve some issues.
- rimo 13y agoYou might want to take a look at https://github.com/philbooth/check-types.js https://github.com/philbooth/check-types.js
- philbo 13y agoI've contributed to a little JS lib [1] that takes a similar approach, but expands all of its predicates with two modifiers: a `maybe` modifier that tolerates null and undefined; and a `verify` modifier that throws if the predicate returns false. I've found it quite useful for eradicating some common boilerplate from my code. e.g.: var check = require('check-types'); check.unemptyString(''); // returns false check.maybe.unemptyString(); // returns true check.verify.unemptyString(''); // throws Error check.verify.maybe.unemptyString(); // doesn't throw [1] https://github.com/philbooth/check-types.js https://github.com/philbooth/check-types.js
- mneary 13y agoWith Typical[1], I took a different approach enforcing types on the functions. [1]: https://github.com/mattneary/Typical https://github.com/mattneary/Typical
- rimo 13y agoThe approach is interesting but the syntax makes it hard to use. Why not make the first arguments the types like one would expect?
- mneary 13y agoI went back and forth with that. I think I went with postfix because there exists another syntax which looks prefix: T([Number, Number])(function(x) { return x; }) For this method, a function type is defined and then serves as a constructor that accepts a function as argument.
- tomcdonnell 13y agoHere's how I do type checking in Javascript. function doStuffWithAVarietyOfParameters(s, a, b, i, ni, p) { var f = 'contractCategoriesAndAddExpandButtons()'; UTILS.checkArgs(f, arguments, ['string', 'array', 'boolean', 'int', 'negativeInt', 'Particle']); // Do stuff. } For functions with many parameters, I like to pass the parameters inside an object and give the keys descriptive names. function doStuffWithAVarietyOfParameters(o) { var f = 'contractCategoriesAndAddExpandButtons()'; UTILS.validator.checkObject ( o, { arrayParam : 'array' , boolParam : 'boolean' , nullOrFloatParam: 'nullOrFloat', particleParam : 'Particle' , positiveIntParam: 'positiveInt', stringParam : 'string' } ); // Do stuff. } Both functions will throw an exception if the arguments list is not as expected. The code can be found via the links below. https://github.com/tomcdonnell/lib_tom/blob/master/js/utils/utils.js https://github.com/tomcdonnell/lib_tom/blob/master/js/utils/... https://github.com/tomcdonnell/lib_tom/blob/master/js/utils/utilsValidator.js https://github.com/tomcdonnell/lib_tom/blob/master/js/utils/... I do type checking similarly in PHP. http://tomcdonnell-tech.blogspot.com.au/2011/09/favourite-phpjavascript-functions.html http://tomcdonnell-tech.blogspot.com.au/2011/09/favourite-ph...
- CodingFu 13y agoBTW, I've written a module for the Node.js with similar API: https://github.com/CodingFu/typeof https://github.com/CodingFu/typeof
- nailer 13y agoI use 'kind' from Agave for this. It uses the same technique (Object.prototype.toString() plus edge case handling) but ships with lots of units tests to prove it: https://agavejs.org https://agavejs.org ### Numbers kind(37) === 'Number' kind(3.14) === 'Number' kind(Math.LN2) === 'Number' kind(Infinity) === 'Number' kind(Number(1)) === 'Number' kind(new Number(1)) === 'Number' ### NaN kind(NaN) === 'NaN' ### Strings kind('') === 'String' kind('bla') === 'String' kind(String("abc")) === 'String' kind(new String("abc")) === 'String' ### Booleans kind(true) === 'Boolean' kind(false) === 'Boolean' kind(new Boolean(true)) === 'Boolean' ### Arrays kind([1, 2, 4]) === 'Array' kind(new Array(1, 2, 3)) === 'Array' ### Objects kind({a:1}) === 'Object' kind(new Object()) === 'Object' ### Dates kind(new Date()) === 'Date' ### Functions kind(function(){}) === 'Function' kind(new Function("console.log(arguments)")) === 'Function' kind(Math.sin) === 'Function' ### undefined kind(undefined) === 'undefined' ### null kind(null) === 'null'
- johnnymonster 13y agoIt appears you are doing this because you are never really sure what sort of data is being sent to your application. I would dump this sort of idea in favor of schema validation. if you are going to get data from a client application where the client developer can screw up the data, why not just validate the data as a whole before accepting it then you know your structure. I really just can't stand all the type checking all over the place, it makes the code feel like all your reading is type checking and not the real logic of what is going on in this function. Additionally, returning an empty string when i mess up a data structure is horrible for debugging. I would have to actually go into the code now to figure out why an empty string came back instead of processing as I thought it should. if your really worried about exposing errors to the end user. wrap that whole thing up in a try catch block instead, log an error and don't display anything to the end user.
- macspoofing 13y ago>It appears you are doing this because you are never really sure what sort of data is being sent to your application. He's doing this because he wants type safety in his functions. If you have that, you eliminate one source of bugs. >I really just can't stand all the type checking all over the place, it makes the code feel like all your reading is type checking and not the real logic of what is going on in this function. That's a big problem with his approach. It's not scalable, and you can't rely on it (inevitably, developers will take shortcuts and you're going to have a hodgepodge of type checks littering your code). He might as well use TypeScript or Dart or Google Closure Compiler. >I would have to actually go into the code now to figure out why an empty string came back instead of processing as I thought it should. Problem number two with his approach. He doesn't actually have compile-time checks which is where you want your type-checks to be. Instead it's all run-time (and he ignores the errors), which raises the question, what the heck is he actually gaining from all this? Again, he should just use TypeScript or Dart or Google Closure Compiler.
- ceautery 13y agoA simple "constructor.name" query covers most of this. You still need edge case checkers for null, Nan, and Infinity, but... function type(a) { var t = a.constructor.name.toLowerCase(); return t.match(/^html/i) ? 'element' : t } ...handles the rest. Still, I liked this post quite a bit; it shows pretty clearly how odd type checking can be in a loosely typed language.
- voidr 13y agoFirstly: they could just start using TypeScript if they really care that much about type erros, since TS is a superset of JavaScript they can start using it with their existing code, so there is no excuse not to use it. Secondly: it's ridiculous that their way of handling type errors is by just silently hiding them. They could be making a lot of errors that will become really hard to find this way. Thirdly: performing type checking on runtime in JavaScript is just stupid, things like this could be performed at "compile time" with TypeScript or the Google Closure Compiler.