walterra

I develop data visualizations. This is my personal blog. More about me.

An opinionated approach to have type safety in native JavaScript.

27. April 2015

Preface

I have to admit, I love JavaScript and do not completely grasp the bashing. It supports my style of thinking and prototyping. I like its flexibility, it gives me a lot of subjective freedom. But as Voltaire and others say, with great power comes great responsibility. By not forcing any models, certain styles or patterns on you there is a high probability of your project ending up in total spaghetti or even worse risotto code.

Therefore I’m a big fan of simple patterns and modularity. I don’t like monolithic frameworks which force you to use a certain structure or style of code. To understand what I like about simple patterns have a look at Bostock’s Towards Reusable Charts and Elliot on Inheritance in JavaScript. Over time I found a nice personal approach inspired by the mentioned ideas to structure code and work with OOP.

Originally coming from the PHP world (behave!) I like JavaScript being untyped/dynamically typed (whatever you prefer calling it). I understand that native statically typed languages might perform better. But I don’t like language fragmentation and I don’t understand why you would want to program in a different syntax or dialect if you’re „compiling“ to native JavaScript later on anyway (looking at you, TypeScript). IMHO there’s no advantage regarding the final compilation and you have to learn a new type of language in addition to creating tool overhead.

That doesn’t mean that I don’t see a need for type safety. It’s just that I’d like to keep using native JavaScript. That’s why I came up with Avocado.

Avocado

Avocado is a small library and pattern guide to help you with type safety and data validation in native JavaScript. It is very very early in development, a prototypish state, a proof of concept. I post this so I’ll be able to find out if other developers share my mindset (see preface) and if it’s worth following this approach. I’ll accept if you tell me this is totally nuts too of course.
Avocado internally uses unified getters/setters and object factories to create a simple interface (interface not in the sense of OOP). Looking back how I came here, in my experience the underlying code might be a little hard to wrap your head around. But once you got it, this kind of programming leads to a more declarative style in an almost natural manner. Which I prefer.

Avocado gives you some tools to work with types, for example:

> av.int(10)();
< 10

> av.int(.1)();
< Uncaught d is not an integer

> av.int('a')();
< Uncaught d is not a number

Avocado allows you to create your own types.

var adultAge = function (i){
  return av(i, function (d){
    if (av.int(d)() >= 18) return d;
    else throw "not old enough!";
  })
};

> adultAge(17)();
< Uncaught not old enough!

> adultAge(18)();
< 18

The real fun starts as soon as we combine this with objects;

var Person = function (i){
  return av.map(i, {
    fullName: av.string,
    age: av.int
  });
};

Using this approach we can define requirements for objects and have them checked upon creation.

var gandalf = Person({
  fullName: "Gandalf the Grey",
  age: 2019
});

We get back an object with setters/getters for each property.

> gandalf.fullName();
< Gandalf the Grey

Each property uses its corresponding type validator.

> gandalf.fullName('Gandalf the White');
> gandalf.fullName();
< Gandalf the White

> gandalf();
< {name: "Gandalf the White", age: 2019}

How do you like that? Have a look at the github repository, to try it out yourself: https://github.com/walterra/avocado

In my next post I’ll talk about on how to move on with this approach in regards to inheritance and nested objects (think Hobbits, Wizards, Orcs!).

Again, a reminder: This emerged as an experiment, a proof of concept, it’s far from really ready. So don’t be too harsh on the code and me :). I know it’s also a bit vague whether this is about type safety, static types or just type validation, I’d still love to hear your thoughts and where this could lead!

PS: If you like this, give it an upvote on Hacker News

Filed under: Code
  • Pingback: 2p – Show HN: An opinionated approach to have type safety in native JavaScript | Profit Goals()

  • Omar Meky

    It appears you are adding a lot of processing overhead this way. Consider using typescript where the validation is done at compile time so that runtime is not affected.

  • Avodaco? :)

  • You attribute Anthony Aceldy for the inheritance article, when it is in fact Eric Elliot who wrote it. Aceldy is the fellow who took the mouse photo.

  • walterra

    haha thanks for the catch :)

  • guyAtHockeyBiasDotCom

    That is the first thing that came to mind for me as well.

  • walterra

    thanks, fixed :)

  • walterra

    Thanks for the feedback. I see what you mean with checking types at compile time. I sort of see it as a mixture of type+data checking (see last paragraph of the blog post) so I think it’s still useful at runtime. What do you think?

  • walterra

    Additionally (I don’t know it that well) I think TypeScript creates runtime overhead as well, see http://research.microsoft.com/apps/video/default.aspx?id=226836

  • obiwanginobli

    have you ever tried to put a square peg in a round hole, and wound up with a rounded square and a squircled hole?

  • *thumbs up*

  • walterra

    I saw Interstellar so I thought it might work :)

  • Benjamin Clos

    The entire concept behind Typescript’s static typing is flawed, and largely useless in data intensive applications, or modules.

    If you are mashing up various external apis or building a configurable module, it’s considerably more sensible to have the option to apply dynamic type safety.

    So instead of this „overloaded function“ pattern (jQuery anyone?) where you account for nearly any combination of arguments, instead you get a sensible, traceable error with fewer lines of code.

    In the tradeoff of overloading vs dynamic type checking vs laissez faire (and let the JS runtime handle it), dynamic type checking is much more elegant.

    @walterra:disqus I also took a swing at this a month or so ago myself with atypical, and look forward to seeing how your idea evolves.

  • Yahiko Uzumaki

    Run-time checking is not really useful if you need to know wether your code is safe or not. You need static type checking at compile time to detect and fix typing errors.

  • Pingback: Three Short Links: April 28, 2015 - Apprenda()



About me.
I work at Elastic as a JavaScript Engineer within the Machine Learning team. My current focus is on developing visualization interfaces for anomaly detection in time series data.

Get in touch:
twitter.com/walterra
facebook.com/walterra
walter@rafelsberger.at