External Modules in Typescript when targeting ES6

时间:2015-12-10 01:49:55

标签: typescript ecmascript-6 koa es6-module-loader koa2

With the release of Typescript 1.7 and async/await support, I thought it would be a good time to try out Typescript with koa@2.

I have a really simple setup and it kind of works already:

// app.ts

/// <reference path="../typings/koa.d.ts" />

import Koa from 'koa';

const app = new Koa();

Because koa is not written in Typescript, I had to make a small definition file:

// koa.d.ts
declare module 'koa' {

  interface Context {
    // ctx
  }

  export default class Koa {
    constructor();

    listen(port: number): any;
    use(Function: (ctx: Context, next: () => Promise<void>) => void): Function;
    use(Function: (ctx: Context) => void): Function;
  }
}

This all works well in the IDE (no errors, autocomplete works too). However, when I compile (target => ES6) it to Javascript, the compiled file can't be executed:

// generated app.js
var koa_1 = require('koa');
const app = new koa_1.default();

When I try to run it, i get the following error:

/Users/andreas/IdeaProjects/project/dist/app.js:16
const app = new koa_1.default();
            ^

TypeError: koa_1.default is not a function
    at Object.<anonymous> (/Users/andreas/IdeaProjects/project/dist/app.js:16:13)
    at Module._compile (module.js:425:26)
    at Object.Module._extensions..js (module.js:432:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:313:12)
    at Function.Module.runMain (module.js:457:10)
    at startup (node.js:138:18)
    at node.js:974:3

It doesn't work because koa_1.default() is not a function, it should just be koa_1(). (I'm also not sure why it renames the variable like that). If I make this simple change in the generated app.js, everything works.

I was reading through many article related to typescript and external modules, but I still seem to miss something. I found this example on one of the websites: source

// foo.js
export var bar = 'bar'  
export default 'foo';

// app.js
import foo from './foo';  
// foo => 'foo'
import * as fooModule from './foo';  
// fooModule => { bar: 'bar', default: 'foo' }
import { default as defaultFoo } from './foo';  
// defaultFoo => 'foo'

This kind of explains why it is adding the .default, but from my understanding it is doing it in the wrong situation. (It is not needed when I do import Koa from 'koa';, but when I do import * as Koa from 'koa';

When I change the import statement in my app.ts to import * as Koa from 'koa'; the generated app.js works, but the Typescript compiler and IDE give me the following errors.

src/app.ts(13,13): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
src/app.ts(23,16): error TS7006: Parameter 'ctx' implicitly has an 'any' type.
src/app.ts(23,21): error TS7006: Parameter 'next' implicitly has an 'any' type.
src/app.ts(32,9): error TS7006: Parameter 'ctx' implicitly has an 'any' type.

So currently, I can choose if my development environment works or if the generated Javascript works, but not both.

What is the best way to deal with this problem?

I think the easiest thing would be to change the koa.d.ts definition file to match import * as Koa from 'koa';. However, I did not manage to do that.

Thanks for your help!

1 个答案:

答案 0 :(得分:0)

改变这个:

 export default class Koa {

到这个

class Koa {
// ...
namespace Koa { // add all your export interface inside
// ...
export = Koa;

继续使用import * as Koa语法。