Typescript: ES6 module declarations should be marked to exclude them from `allowSyntheticDefaultImports`

Created on 25 Sep 2018  路  5Comments  路  Source: microsoft/TypeScript

This is the restated #27293. CC @ryanelian


TypeScript Version: master (471bc64)


Search Terms: esModuleInterop allowSyntheticDefaultImports error undefined default import export

Code: In the b subdirectory, compile with tsc -b . and run with node index.js.

// tsconfig.common.json
{
    "compilerOptions": {
        "composite": true,
        "declaration": true,
        "target": "es6",
        "module": "commonjs",
        "esModuleInterop": true
    }
}

// a/tsconfig.json
{
    "extends": "../tsconfig.common.json",
    "files": [
        "index.ts"
    ]
}

// a/index.ts
export const foo = 42;

// b/tsconfig.json
{
    "extends": "../tsconfig.common.json",
    "references": [
        { "path": "../a" }
    ],
    "files": [
        "index.ts"
    ]
}

// b/index.ts
// Actual: compile OK.  Expected: compile error.
import A from "../a";
// Actual: runtime error.
console.log(A.foo);

Expected behavior: The generated a/index.d.ts uses some new syntax to mark the module as an ES6 module, so allowSyntheticDefaultImports does not apply to it and the default import in b/index.ts is a compile error.

Actual behavior: allowSyntheticDefaultImports applies to module a, so at compile time, the default import is accepted and resolves to the entire module, but at runtime, A.foo raises an error:

REDACTED/b/index.js:7
console.log(a_1.default.foo);
                        ^

TypeError: Cannot read property 'foo' of undefined

Playground Link: N/A, multiple files

Related Issues: #27293

In Discussion Suggestion

Most helpful comment

For anyone running into this issue: you're doing it wrong.

The error is that you're using import X from 'module' when module does _not_ have a default import. import X does not work like const X = require()

Solution: either use:

import * as X from 'module'

or maybe import it as a CJS module with:

import X = require('module')

The bug is that the compiler should error, _not_ that it doesn't work at runtime.

All 5 comments

Please note: The marker actually already exists, we just don't emit it. If the declaration file has export const __esModule: true, then we're guaranteed to treat it like a module and not create a synthetic namespace in the typesystem.

I am running into this issue as well

I'm running into the same issue. I think one way to fix this is to update the __importDefault tslib helper to be a bit more lenient? I'm not 100% sure if this is the behaviour we want though.

I.e., update https://github.com/Microsoft/tslib/blob/ca03390c0bcf14ae0ef8090dec52de5059ed2e96/tslib.js#L220-L222 from

return (mod && mod.__esModule) ? mod : { "default": mod };

to

return (mod && mod.__esModule && mod.hasOwnProperty("default")) ? mod : { "default": mod };

As discussed in https://github.com/Microsoft/tslib/pull/64, the workaround I suggested above is not the right solution to this problem.

For anyone running into this issue: you're doing it wrong.

The error is that you're using import X from 'module' when module does _not_ have a default import. import X does not work like const X = require()

Solution: either use:

import * as X from 'module'

or maybe import it as a CJS module with:

import X = require('module')

The bug is that the compiler should error, _not_ that it doesn't work at runtime.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

uber5001 picture uber5001  路  3Comments

MartynasZilinskas picture MartynasZilinskas  路  3Comments

dlaberge picture dlaberge  路  3Comments

blendsdk picture blendsdk  路  3Comments

remojansen picture remojansen  路  3Comments