James Croft

CoffeeScript and extensions to the Number prototype

UPDATE: This is now fixed in CoffeeScript 0.9.6.

3.days() // Gets compiled into (3).days()

Thanks @jashkenas


Due to the way that JavaScript is interpreted, any extensions to the Number prototype can only be called when the number is wrapped in parenthesis.

Number.prototype.add = function(num){
  return this + num
};

(1).add(1); // => 2
1.add(1);   // => SyntaxError

You might think it’s a bad idea to modify the Number prototype but in some situations it can be useful. For example, datejs is a library that allows you to do such things as:

(3).days().ago() // => Sat Dec 11 2010 16:01:01 GMT+0800 (HKT)

But, you must remember to use the parenthesis

3.days().ago() // SyntaxError

I’ve been writing a lot of CoffeeScript recently and today I was writing a test suite for some time sensitive code. In order to simplify working with the dates, I was using datejs in test suite.

# CoffeeScript
journey =
  id: 1
  startTime: (180).minutes().ago()

However, this CoffeeScript will compile into the following JavaScript

// JavaScript
journey = {
  id: 1,
  startTime: 180.minutes().ago()
};
// Syntax error upon execution

Note that the parenthesis were removed, this causes a syntax error when the code is executed.

The only way I have found to get round this is to use backticks to escape any code that calls an extension to the Number prototype. Backticks tell the CoffeeScript compilier to ignore the code and treat it as is.

#CoffeeScript
journey =
  id: 1
  startTime: `(180).minutes().ago()`

will compile to the required:

journey = {
  id: 1,
  startTime: (180).minutes().ago()
};

This works but it’s not pretty. If you using any libraries that extend the Number prototype then you are going to end up with a lot of backticks in your code.

Let me know on twitter or email if there’s a better solution to this.