I have a TypeScript class that's part of an npm package. For maintenance, I broke up the class into multiple classes, and I built up the ultimate exported class through inheritance. I don't think this matters to my question, but I figure it's better to disclose this bit of information. I defined the class in ChildClass.ts like this:
export default ChildClass extends ParentClass{…}
Tsc has an outDir of "build."
The package.json file has a property "main": "build/ChildClass.js"
Using both npm link and npm pack and I can deploy the package and consume it with no problem in a TypeScript demo package. However, if I try to use the package in a JavaScript demo,
const ChildClass = require('my-package')
const childClass = new ChildClass()
I get the error
Cannot use 'new' with an expression whose type lacks a call or construct signature.ts(2351)
If I change the new statement by adding .default like so:
const childClass = new ChildClass.default()
It works. I figured this out by looking at the compiled Javascript. Having to use .default struck me as an unreasonable thing to expect (the hypothetical) JavaScript consumers of my package to know. I also discovered that if I avoided export default and just used export then the package works more predictably, so that's what I did. Now I can use
const {ChildClass} = require('my-package')
const childClass = new ChildClass()
and the similar syntax
import {ChildClass} from 'my-package'
const childClass = new ChildClass()
in typescript.
Still, I would like to know what this magic .default property is and why I need it.
Also, all other references I found to this error didn't seem relevant to what I was seeing; I thought documenting this might help someone else that runs across a similar error.
require()andexports) is not compatible with ES6 default exports. The solution to down-compile but still allow ES6 spec compliant module loaders to work is to emit__esModuleon the exported value. Babel does the same thing. IMO just avoid default exports, they aren't very useful and create problems.