Typescript Definition

Not 100% complete, but should work for anything that is not super complex.

Any idea where / if this should live in the repo?  I plan to submit it to [DefinitelyTyped](https://github.com/borisyankov/DefinitelyTyped) so that it can easily be added to other projects.

Here is some example typescript using the definitions in the file
``` typescript
/// <reference path="nunjucks.d.ts" />

import nunjucks = require('nunjucks');

var env = nunjucks.configure('/test', {
  somethingStupid: true,
  tags: {
    blockStart: '<%',
    blockEnd: '%>',
    variableStart: '<$',
    variableEnd: '$>',
    commentStart: '<#',
    commentEnd: '#>'
  }
});

env.addFilter('shorten', (str, count) => {
  return str.slice(0, count || 5);
})

env.getFilter('shorten');

class MyExtension implements nunjucks.Extension {
  tags = ['remote'];

  parse(parser, nodes, lexer) {
    // get the tag token
    var tok = parser.nextToken();

    // parse the args and move after the block end. passing true
    // as the second arg is required if there are no parentheses
    var args = parser.parseSignature(null, true);
    parser.advanceAfterBlockEnd(tok.value);

    // parse the body and possibly the error block, which is optional
    var body = parser.parseUntilBlocks('error', 'endtruncate');
    var errorBody = null;

    if (parser.skipSymbol('error')) {
      parser.skip(lexer.TOKEN_BLOCK_END);
      errorBody = parser.parseUntilBlocks('endremote');
    }

    parser.advanceAfterBlockEnd();

    // See above for notes about CallExtension
    return new nodes.CallExtension(this, 'run', args, [body, errorBody]);
  }

  run = function (context, url, body, errorBody) {
    var id = 'el' + Math.floor(Math.random() * 10000);
    var ret = new nunjucks.runtime.SafeString('<div id="' + id + '">' + body() + '</div>');
    var ajax = new XMLHttpRequest();

    ajax.onreadystatechange = function () {
      if (ajax.readyState == 4) {
        if (ajax.status == 200) {
          document.getElementById(id).innerHTML = ajax.responseText;
        }
        else {
          document.getElementById(id).innerHTML = errorBody();
        }
      }
    };

    ajax.open('GET', url, true);
    ajax.send();

    return ret;
  };
}

env.addExtension('my-ext', new MyExtension());

var ext: nunjucks.Extension = env.getExtension('my-ext');

var tmpl: nunjucks.Template = env.getTemplate('page.html');

env.getTemplate('async-page.html', function (err, tmpl) { });

// This would be an actual express app in any real example
var app = {};
env.express(app);

var tmpl: nunjucks.Template = new nunjucks.Template('Hello {{ username }}');

tmpl.render({ username: 'James' });

new nunjucks.FileSystemLoader('pathA');
new nunjucks.FileSystemLoader(['pathA', 'pathB'], false);

new nunjucks.WebLoader('/templates', false);

class MyFirstLoader extends nunjucks.Loader {
  init() {
    // setup a process which watches templates here
    // and call `this.emit('update', name)` when a template
    // is changed

    this.emit('update', name);
  }

  getSource(name: string) {
    // Load them template
    return {};
  }
}

class MySecondLoader extends nunjucks.Loader {
  constructor() {
    this.async = true;
    super();
  }

  getSource(name: string, callback?: Function) {

    return {};
  }
}
```