Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.ts file isn't treated as TypeScript module

Here is SystemJS + TypeScript plunk, created from official Angular plunk template.

It throws

(SystemJS) SyntaxError: Missing initializer in const declaration

at eval ()

...

error and obviously evaluates .ts file as ordinary JavaScript when the file doesn't contain import or export statements:

main.ts

const foo: boolean = 'foo';

console.log(foo);

config.js

System.config({
  //use typescript for compilation
  transpiler: 'typescript',
  //typescript compiler options
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  paths: {
    'npm:': 'https://unpkg.com/'
  },
  //map tells the System loader where to look for things
  map: {

    'app': './src',
    ...
  },
  //packages defines our app package
  packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts'
    },
    ...
  }
});

index.html

...
<script src="https://unpkg.com/[email protected]/dist/system.js"></script>
<script src="config.js"></script>
<script>
System.import('app')
  .catch(console.error.bind(console));
</script>
...

But the same plunk is fine when the file has signs of ES6 module:

main.ts

const foo: boolean = 'foo';

console.log(foo);

export default null;

Obviously, if a file has .ts extension, I would prefer to evaluate it as TypeScript, whether it imports something or not.

Why does this happen in this setup? How can this be fixed?

like image 541
Estus Flask Avatar asked Apr 14 '17 23:04

Estus Flask


2 Answers

SystemJS will probably work as follows:

> System.import('app')
  - where is 'app'?
> map: { 'app': './src', ...
  - Okay, 'app' is './src'
  - './src' ??
> packages: { app: { main: './main.ts',
  - Aha, './src/main.ts'
> ./src/main.ts
  - Which format??
  - 'system' ? -> No
  - 'esm' ? -> No (if YES, use transpiler: 'typescript')
  - 'amd' ? -> No
  - 'cjs' ? -> No
  - 'global' ? -> Yes -> No transpiler needed.
> evaluate ./src/main.ts
  - What is ':string' in JavaScript?
  - Exception!!!

Module format detection

When the module format is not set, automatic regular-expression-based detection is used. This module format detection is never completely accurate, but caters well for the majority use cases.

If auto-detection fails, you must specify it manually.

Method 1: Add hints to source

ex1: add export (from question)

const foo: boolean = 'foo';
console.log(foo);
export default null;

ex2: add export

export const foo: boolean = 'foo';
console.log(foo);

Method 2: Add format configuration

ex1: packages / path / meta / pattern(./main.ts or ./*.ts) / format

packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts',
      meta: {
       './main.ts': {
           format: 'esm'
        }
      } 
    }

ex2: packages / path / format

packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts',
      format: 'esm'
    }
}

ex3: meta / pattern (need app/ prefix) / format (outside packages)

meta: {
    'app/main.ts': {
        format: 'esm'
    }
}
like image 155
thatseeyou Avatar answered Nov 15 '22 10:11

thatseeyou


Disclaimer: This comes from just a little debugging, I'm not actually experienced in the subject so any corrections to my understanding are welcome.

SystemJS will only perform transpilation if the module format is determined properly. If the module format is not informed, it uses a fast heuristic to try and determine it (basically, a regular expression over the source). This heuristic works when you have the import statement and fails when you don't. The actual fix for your set up is to add the module format explicitly to the package like so:

app: {
  main: './main.ts',
  defaultExtension: 'ts',
  format:'esm' // << Module format.
},
like image 27
Fredy Treboux Avatar answered Nov 15 '22 09:11

Fredy Treboux