51 comments

[ 4.8 ms ] story [ 111 ms ] thread
Who would've thought that after years of cursing them for spamming me, I would read something interesting on their tech blog.
Sounds great! Looks like you can find similar functionality in underscore.js, although they ask you to do the checking explicitly, ie `isBoolean(true)`.
Great 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.
Well, 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.

Agree 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.
It'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.
Static 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.
You can use a different observer pattern sometimes that can be caught by static typing, like Signals
Sufficiently 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.
Sure - and you can test types in your unit tests using the OP's technique. :)
Firstly good spot on the '||' instead of an '&&'. Will fix that now.

Secondly I completely agree about wanting a program to crash noisily and detectably in development, but in production I would prefer that the error is handled and the user can continue to use the app.

Finally I also agree that if type checking is really important to you, a compile to JS language like TypeScript or Dart are the best options. The techniques / approach I am discussing in this article are really for people who already have a large vanilla JS code base or want to learn a bit more about types in JavaScript.

Just wanted to add that TypeScript is backwards compatible with JS, so having a large vanilla JS code base doesn't really matter - it's already valid TypeScript code, so you can go and start adding type annotations and whatnot.
Typescript is a superset of Javascript. So any vanilla JS code base can be easily ported to Typescript.
> in production I would prefer that the error is handled and the user can continue to use the app.

Maybe that's ok if it's a game or something, but this is a dangerous strategy. How do you know it's ok to use the app if there's an error? You have to very carefully isolate and control where your errors can be, and I'm not sure this approach allows you to do that.

Typescript has its own issues:

  interface IA { }
  interface IB { foo(): void; }
   
  function fn(passedFn: (a: IA) => void) {
    passedFn({}); 
  }
 
  // compiles but throws TypeError at runtime!
  fn((b: IB) => b.foo());
Basically adding "compiler bits" into your dynamically typed language application code.
Typechecking JavaScript is feasible. But will be really hard in practice.

We have worked for years on the Opa technology, cf. 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.

What'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.

Agreed. 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.
I'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.)

Promises & named functions are your friends!

So you can do stuff like this:

  callToRemoteApi().then(processData)
    .then(makeAnotherCallToAnotherApi)
    .then(processAllTheData)
You 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.
Generators and await don't really give anything substantial after promises except less superficially verbose syntax and not even that when using CoffeeScript where `return` and `function(){}` are really light-weight. Actually what issues generators and await solve are same as what CoffeeScript "solves".

Although with generators you "can use normal control flow constructs". Except in most cases you probably use map or forEach instead of loops anyway. And try-catch is really broken.

For me I like static typing because it adds a sanity check of the data getting passed around. Sure, most of the time it catches nothing, but it is nice when it does. Humans will always make mistakes, so static typing improves the amount of help\tools computers can put forth.
the problem is NOT static typing vs dynamic typing but weak typing vs strong typing and type coercion.

In basic ruby ,unless you mess with classes, [1,2]+1 WILL fail , though ruby is not staticaly typed. Ruby is STRONGLY typed, and that's a great thing.

Javascript will do everything it can not to fail:

    String([1,2]) => "1,2"

    + 1 => "1,21"
IMHO

That's madness,because Javascript is basically making a decision for you.That was acceptable in 1995, that is not in 2013.

And that's its biggest flaw.Writing javascript means working against the language.

But there is a reason for that. Javascript is not good at throwing errors or handling them, at all.

So it's not about static vs dynamic typing.

There is no good solution for that problem unless TC39 decides to fix it. Enforcing dependency injection concepts and duck typing might work, but not always. For instance, you could check if a string is a string with

    function(x){
        x=x.substr(); // will throw a TypeError if I pass an Array. 
    }
Before doing anything with x, it might help reduce some mistakes. and you might use it on return types. But it's verbose and doesnt work all the time.
It was not acceptable in 1995, either.
But have you used statically typed langauges? Unless you've used both you won't be aware of the advantages.

The big one for me is inheriting other people's code bases, in dynamic languages they're a complete and utter nightmare, especially when written by incompetent programmers, which seems to make up a worryingly large number of programmers. Or someone just learning and not aware of conventions.

You just can't assume a method or function actually does what it says it does. Or returns what it says it does. And you can't even see what it's expecting or what things are being passed to it. You have to fine-toothcomb the method, it slows you down massively.

I have worked on a fair few bad code bases now and luckily for me the majority of that's been in static languages. It makes it so much easier.

Some of the other advantages of static typing include:

1. having incredibly good auto code completion

2. never having to remember or look up a method signature

3. to refactor massive chunks of code almost completely fearlessly

4. to fix crap code without any fear of breaking anything else

5. as long as you name your methods well, never having to annotate anything mundane (depending on your audience ofc)

There are also other things like that tend to go hand-in-hand because they're usually explicit, like not worrying about implicit conversion (apart from VB with option explicit off).

I've used both quite a lot over the last 10 odd years professionally programming and I've recently been thinking that I would actually prefer a mix, static typing on boundaries like method entry and new object declartion and dynamic everywhere else. I know little about compiler or language design, so I'm not sure it's even possible. C# kinda gets close with the var keyword, but the various disadvantages of static typing still rear their head quite a lot.

As a slight aside, People on HN always seem to talk as if they only write new programs, not maintain old ones. Am I the weird one for frequently having to pick up code that was written by someone else? Who often had coded themselves into a corner and then made up some excuse as to why they couldn't keep the client anymore?

I had to do some stuff in Java at university, it felt too clunky most of the time. :\

When using libraries, their functions always wanted their arguments to be some strange classes or implement some of their interfaces, which always seemed like big overhead to me.

Stuff like Smalltalk, PHP and JavaScript felt much faster in development speed.

...and breaks much more often at runtime.
You actually can't see the advantage of statically typed languages unless you've worked on a non-trivial codebase.

I've never used Smalltalk, but the other two you mention suffer from massive problems when you get to a certain size codebase.

I'm extremely wary of saying this, but I generally think that uni professors/tutors can't program. Basically unless they've written a large open source program or actually worked in the industry for a lot of years, they're probably going to be useless programmers. And even then, there's a good chance they're useless programmers.

That may be a slightly old fashioned view, but most lectures I've seen from unis online tend to completely miss the point of basic concepts (OO being the most common one). And it's rare to meet graduate CS who can actually program anything on their own from scratch. Google's fine, but cut & pasting code you don't understand and changing random stuff as it sounds kinda right, that's not programming, that's a bloody rain dance.

Programming is a skill that needs years of work before you're even vaguely good. And the worst part is you're almost constantly suffering from the Dunning-Kruger effect, thinking you're much, much better than you actually are. I probably still am.

It's one of the reasons we see security holes time and time again, novices don't even realise the problem exists!

For example, I have no idea what to do with crash dump in windbg. I wouldn't even know where to start. Is that a massive knowledge gap? But give me a stack trace of a problem & the source in almost any web language and I'd probably be able to fix it, even if I've never used the programming language before.

Yeah, this is probably true...

But I have to say, my programming prof. was rather fond of Java. Biggest part of the lecture on OOP was about type systems (and I hated it lol).

Most of the stuff I learned about programming, I didn't learn in university, but at work.

But since my experience with Java at university was so bad, I searched for jobs in different languages, like JavaScript.

A few years ago I tried to learn Scala, because it seemed like a better Java to me. But somehow I never got along with it. The type-system seemed logical, but it had so much other stuff around that made starting rather difficult, so I went back to JavaScript.

It actually seems like an overhead but in reality it's designed to help you maintain your software easier: Using interfaces makes your software functionnally dependant meaning that it relies on "theorical functions". On the contrary using directly some library makes your software structurally dependant to one's library. This can be a massive issue if the library you're using is not maintained. If you wanted to switch to another one unless you were using a well defined interface that the other library can implement. You would just have to change a few lines of code vs changing a whole lot of calls to one's lib.

IMO, this is one of the major issue of javascript.

Thats because Javas has a clunky type system and bloated libraries full of design patterns. In languages with better support for higher order functions the bit about needing to pass a strange class is much more lightweight.

IMO, real advantages of dynamic typing vs static typing are

* Simplicity. You don't need to learn a complex type system to start coding.

* Flexibility. Dynamic type systems don't stop you from doing useful things ike polymorphism and generics. In a static type system those need to be build in from day 1.

Completely disagree. Lazy developers not willing to learn a language can not count as argument against statically typed languages. This is a bit like suggesting you should better walk across the country because than you do not need to fuel your car or buy some kind of ticket.

And having to build more advanced type system features on top of a simpler type system is hardly a good thing either - type theory is not trivial and chances that you will get it wrong are large. Even experts in the field make wrong decisions, for example array covariance in Java an C#. And even if you get it right you will usually not enjoy (all) the benefits of compile time type checking and fail only at runtime.

When I had lectures about type-theory in university, it made me even more confident in not using statically typed languages. Those whole contra/covariant problems I read about seemed crazy to me :\

It felt like even the implementers of those type-systems didn't get it right.

Java's type system is extreme with its checked exceptions. Try C# instead. I can see the value of checked exceptions for robustness but if you're just prototyping something it drives you nuts.

The specified classes for arguments is a good thing since you dont have to dig through piles of documentation or code review every method you use to understand their behavior.

What do you expect the arguments of the following function to be: 1. A file descriptor, or 2. A path to a file that will be opened by the function?

def print_log(file): ...

One could argue it's bad naming convention but i see shit like this way too often to think it can be solved by conventions. Documenting doesn't work either for the same reason, documentation becomes more boilerplate than specifying types in a type safe language btw.

Contrast this with the C# equivalent

void PrintLog(File file) { ... }

Bang!, You instantly know that the file parameter is a File-object and you can focus your mind on more important things.

I'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
With Typical[1], I took a different approach enforcing types on the functions.

[1]: https://github.com/mattneary/Typical

The approach is interesting but the syntax makes it hard to use. Why not make the first arguments the types like one would expect?
I 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.
Here'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/...

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-ph...

I 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

    ### 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'
It 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.

>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.

A 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.
Firstly: 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.