Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you write a node module using typescript?

So, the general answer for the other question (How do you import a module using typescript) is:

1) Create a blah.d.ts definition file.

2) Use:

/// <reference path="./defs/foo/foo.d.ts"/>
import foo = require("foo");

Critically, you need both the files foo.d.ts and a foo.js somewhere in your node_modules to load; and the NAME foo must exactly match for both. Now...

The question I would like to have answered is how to you write a typescript module that you can import that way?

Lets say I have a module like this:

- xq/
- xq/defs/Q.d.ts
- xq/index.ts
- xq/base.ts
- xq/thing.ts

I want to export the module 'xq' with the classes 'Base' from base.ts, and 'Thing' from thing.ts.

If this was a node module in javascript, my index.ts would look something like:

var base = require('./base');
var thing = require('./thing');
module.exports = {
  Base: base.Base,
  Thing: thing.Thing
};

Let's try using a similar typescript file:

import base = require('./base');
export module xq {
    export var base = base.Base;
}

Invoke it:

tsc base.ts index.ts things.ts ... --sourcemap --declaration --target ES3 
                                   --module commonjs --outDir dist/xq

What happens? Well, we get our base.d.ts:

export declare class Base<T> {
  ...
}

and the thrillingly unuseful index.d.ts:

export declare module xq {
    var Base: any; // No type hinting! Great. :(
}

and completely invalid javascript that doesn't event import the module:

(function (xq) {
    xq.base = xq.base.Base;
})(exports.xq || (exports.xq = {}));
var xq = exports.xq;

I've tried a pile of variations on the theme and the only thing I can get to work is:

declare var require;
var base = require('./base');
export module xq {
    export var base = base.Base;
}

...but that obviously completely destroys the type checker.

So.

Typescript is great, but this module stuff completely sucks.

1) Is it possible to do with the built in definition generator (I'm dubious)

2) How do you do it by hand? I've seen import statements in .d.ts files, which I presume means someone has figured out how to do this; how do those work? How do you do the typescript for a module that has a declaration with an import statement in it?

(eg. I suspect the correct way to do a module declaration is:

/// <reference path="base.d.ts" />
declare module "xq" {
  import base = require('./base'); 
  module xq {
    // Some how export the symbol base.Base as Base here
  }
  export = xq;
}

...but I have no idea what the typescript to go along that would be).

like image 515
Doug Avatar asked May 19 '14 13:05

Doug


1 Answers

Typescript has really improved since this question was asked. In recent versions of Typescript, the language has become a much more strict superset of Javascript.

The right way to import/export modules is now the new ES6 Module syntax:

myLib.ts

export function myFunc() {
  return 'test'
}

package.json

{
  "name": "myLib",
  "main": "myLib.js",
  "typings": "myLib.d.ts"
}

Dependents can then import your module using the new ES6 syntax:

dependent.ts

import { myFunc } from 'myLib'

console.log(myFunc())
// => 'test'

For a full example of a node module written in Typescript, please check out this boilerplate:

https://github.com/bitjson/typescript-starter/

like image 86
Jason Dreyzehner Avatar answered Sep 21 '22 14:09

Jason Dreyzehner