user2416984 user2416984 - 1 month ago 7
TypeScript Question

Importing external javascript libraries into Typescript for use with node

A while ago we started using Typescript + Electron to write a browser-based desktop application. However, loading external Javascript libraries is often a bottleneck. We use

typings
as much as possible, which does most of the work for us, but some Javascript libraries are not (yet) available this way.
To get started in writing new declaration files, I would first like to try using already existing declaration files from the DefinitelyTyped repository without
typings
. This is a simple example for the abs library:

tsconfig.json:


{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"types": [
"node"
]
},
"files": [
"abs.d.ts",
"abs-tests.ts"
]
}


abs.d.ts:


// Type definitions for abs 1.1.0
// Project: https://github.com/IonicaBizau/node-abs
// Definitions by: Aya Morisawa <https://github.com/AyaMorisawa>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped

declare module "abs" {
/**
* Compute the absolute path of an input.
* @param input The input path.
*/
function Abs(input: string): string;

export default Abs;
}


abs-tests.ts:


/// <reference path="./abs.d.ts" />

import Abs from 'abs';

const x: string = Abs('/foo');


Transcribing and running the outputted Javascript file with node:

npm install @types/node --save-dev;
npm install abs;
tsc -p tsconfig.json;
node abs-tests.js;


Transcribed Javascript file:

"use strict";
var abs_1 = require('abs');
var x = abs_1["default"]('/foo');
//# sourceMappingURL=abs-tests.js.map


Output of node:

<my-path>/abs-tests.js:3
var x = abs_1["default"]('/foo');
^

TypeError: abs_1.default is not a function
at Object.<anonymous> (<my-path>/abs-tests.js:3:25)
at Module._compile (module.js:556:32)
at Object.Module._extensions..js (module.js:565:10)
at Module.load (module.js:473:32)
at tryModuleLoad (module.js:432:12)
at Function.Module._load (module.js:424:3)
at Module.runMain (module.js:590:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:509:3


This is only one of the tests with many different libraries which fails. What is going wrong here? Is it possible to give some explanation on getting Typescript code with external Javascript libraries properly transcribed so it can be used in node?

Answer

Basically, export default was not intended to work for this use case.

Typescript has special export = and import = require() syntax for dealing with node modules.

export = can be used when a node module assigns single object or function to its exports object. That's what abs module does in its index.js:

module.exports = abs;

Type declaration for it can be written like this:

declare module "abs" {
    /**
    * Compute the absolute path of an input.
    * @param input The input path.
    */
    function Abs(input: string): string;

    export = Abs;
}

and used like this

import Abs = require('abs');

const x: string = Abs('/foo');

(side note: you don't need to even /// <reference abs.d.ts if it's included in files in tsconfig.json)

If you for some reason have to use it as export default, you won't be able to do it with typescript alone - you would need to compile it to es6 and use yet another transpiler like Babel that supports export default compatibility with node. You can find details in this typescript issue and this blog post.