Tristan Shelton
Tristan Shelton

Reputation: 337

How can I avoid always having to import my own code in Typescript?

So I was recently hacking on a large Typescript project (https://github.com/BabylonJS/Babylon.js) and I noticed that they don't ever have to import anything, they just use their namespace and the rest is (seemingly) magic.

It got me thinking that I would like to use something similar for myself, so I started a simple typescript project to try it out.

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "src",
    "outFile": "server.js"
  }
}

src/main.ts

module Test {
  console.log('Main started')
  const server:Server = new Server()
}

src/Server.ts

// import * as http from 'http'

module Test {
  export class Server {
    constructor() {
      console.log('Server initialized')
    }
  }
}

If I build this Typescript project then I get output like the following:

// import * as http from 'http'
var Test;
(function (Test) {
    var Server = /** @class */ (function () {
        function Server() {
            console.log('Server initialized');
        }
        return Server;
    }());
    Test.Server = Server;
})(Test || (Test = {}));
var Test;
(function (Test) {
    console.log('Main started');
    var server = new Test.Server();
})(Test || (Test = {}));

So far, so good. The trouble is that I want to take advantage of some external modules, in this case namely the http module, so I uncomment the import line above and now Typescript reports:

src/server/Server.ts(1,1): error TS6131: Cannot compile modules using option 'outFile' unless the '--module' flag is 'amd' or 'system'.

Node uses the commonjs module system, so obviously setting either of those flags isn't going to help me much. I have none the less tried them as well as various other combinations of flags, but to no avail. I noticed that BabylonJS doesn't really use external imports like that, opting instead to declare them as external and provide them globally at execution time as script tags. Is there maybe an analogue to that for Node?

Upvotes: 0

Views: 1585

Answers (2)

Tristan Shelton
Tristan Shelton

Reputation: 337

The solution that worked for me is this:

Server.ts

declare var http: any;

namespace Test {
  export class Server {
    constructor() {
      console.log('Server initialized')
      const server = http.createServer()
      server.listen()
    }
  }
}

Then I simply provide http at runtime, for example by prepending a var http = require('http') to the output. Thanks to artem for a nudge in the right direction.

Upvotes: 0

artem
artem

Reputation: 51619

You can't have these two things at the same time, namely

How can I avoid always having to import my own code in Typescript?

and

I want to take advantage of some external modules

You can avoid imports only by not using external modules, and the result will be one giant script file that can use external dependencies only as globals created by scripts loaded via script tag, as you already noticed.

The language does not allow you to use external modules when you do this. If you have an import of external module at the top level, your file becomes a module and there is no way it could use code from your other files without importing them. And having import of external module inside a namespace is not allowed AFAIK.

That said, I don't think your question - "How can I avoid always having to import my own code in Typescript?" - has a valid premise. CommonJS module system is the solution for preventing large projects from becoming unmaintainable mess. It does not matter if some part of a project is your own code or some external dependency - if it's a separate part with well-defined interface, it should be packaged and consumed as a module.

Upvotes: 1

Related Questions