Typescript: Compiler allows for using a value before it is imported

Created on 31 May 2017  路  7Comments  路  Source: microsoft/TypeScript

TypeScript Version: 2.3.4

Code

// foo.ts
console.log(BAR);
import {BAR} from './bar';
// bar.ts
export const BAR = 'bar';
// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true
  }
}

Expected behavior:

TypeScript should reject foo.ts, because it is referring to BAR before it is initialized.

Actual behavior:

tsc raises no errors, and generates the following foo.js file:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
console.log(bar_1.BAR);
var bar_1 = require("./bar");

This fails at runtime with a TypeError.

Bug ES Modules Transforms

Most helpful comment

Ideally we would hoist the imports, but not change the emit order. This is what already happens for AMD and SystemJS.

All 7 comments

Note that when I first encountered this issue, it was in code like this:

// ...
import BAR = innerNamespace.BAR;
// ...
import {innerNamespace} from './bar';
// ...

So it wasn't as obvious what was wrong.

ES6 imports are hoisted, so the code in foo.ts is valid and should run without errors. The problem here seems to be with the emitted code, which does not hoist the import. Not sure if changing the emit order would be problematic when emitting to other module systems like CommonJS.

FWIW I was curious what babel emits for foo.ts, and it correctly hoists the import, emitting the following JS code (see repl here):

'use strict';

var _bar = require('./bar');

console.log(_bar.BAR);

That's interesting, thanks for the info!

I guess changing the emit order would technically be a breaking change, since importing a module can have side effects. But I'm not sure how common this is in practice.

Ideally we would hoist the imports, but not change the emit order. This is what already happens for AMD and SystemJS.

I just found a similar surprise, and a place where TS should throw and doesn't:

function useA() {
  // using `a` before it is declared surprisingly doesn't error in either TS or the 
  // DevTools console
  console.log(a);
}

useA(); // This does error at run time and should error at compile time

const a = 1;
useA();

It looks like this issue is scheduled to be closed soon with https://github.com/microsoft/TypeScript/pull/39764 which tweaks import hoisting, but this fix will NOT fix the issue described by @appsforartists, which is the same bug I've experienced in my code.

Are there plans to fix this error?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dlaberge picture dlaberge  路  3Comments

uber5001 picture uber5001  路  3Comments

Roam-Cooper picture Roam-Cooper  路  3Comments

MartynasZilinskas picture MartynasZilinskas  路  3Comments

bgrieder picture bgrieder  路  3Comments