How to import CommonJS module that uses module.exports= in Typescript
Asked Answered
P

1

22

The following produces valid, working ES5 but emits the error below. I'm using Typescript 1.7.5 and I think I've read the whole language spec and I cannot figure out why this error is produced.

error TS2349: Cannot invoke an expression whose type lacks a call signature.

a.js (ES5 ambient module with default export)

function myfunc() {
  return "hello";
}
module.exports = myfunc;

a.d.ts

declare module "test" {
    export default function (): string;
}

b.ts

import test = require("test");
const app = test();

b.js (generated ES5):

var test = require("test");
var app = test()
Patrizia answered 14/2, 2016 at 22:12 Comment(4)
What line is this error on?Spirituel
Line 2 of test.ts. at test()Patrizia
BTW, pretty confusing that your post uses the base name "test" for all three of your files. The third file, that imports "./test" and is called "test.ts", is surely actually something else. :)Jerejereld
@CSnover I agree it's unclear, so I've edited the file names to a and b. a is an ES5 commonjs module with no preexisting type declaration file. b is typescript consuming a. Also, the require() in b.ts is changed from "./test" to "test" as it should be a string literal for an external ambient module. I'm surprised it worked with "./test" as the relative path to test.js, but it worked. But this is better because it's the recommended way from the Typescript spec.Patrizia
J
10

module.exports exports a literal value in a CommonJS module, but export default says you are exporting a default property, which is not what your JavaScript code actually does.

The correct export syntax in this case is simply export = myfunc:

declare module "test" {
    function myfunc(): string;
    export = myfunc;
}
Jerejereld answered 15/2, 2016 at 5:14 Comment(3)
That works. Thank you. I think the Typescript spec really led me astray here. Regarding export assignments it says, "Export assignments exist for backward compatibility with earlier versions of TypeScript." (reference), implying it's the old way and you should not use export assignments in new code. This answer is closely related.Patrizia
Also, for the future reader, module.exports= in ES5 is not a "default export", which is an ES6 term. Typescript spec explains the default entity here.Patrizia
AFAICT doing this requires "esModuleInterop": true in your TS compilerOptions. Or am I doing something wrong?Lindeman

© 2022 - 2024 — McMap. All rights reserved.