vue-cli: Subtle error when importing typescript definition file into vue file

Version

3.0.0-rc.12

Node and OS info

Node v10.8.0 / Npm 6.3.0 / Linux WS-001 4.17.13-arch1

Steps to reproduce

  1. vue create test
  2. Add the following to src folder (a simple typescript declaration file, named MyEnums.d.ts):

  export const enum MyEnums {
    C0 = 'ABC',
    C1 = 'DEF'
  }

  1. Add the following to main.ts in src:

  import { MyEnums } from '@/MyEnums';

  interface MyIf {
    enums: MyEnums,
    name: string,
  }

  let p0: MyIf = {
    enums: MyEnums.C0,
    name: 'My name',
  }

  1. Run npm run serve, and you get the error:
  This dependency was not found:

  * @/MyEnums in ./src/main.ts

  1. Rename MyEnums.d.ts to MyEnums.ts
  2. Run npm run serve, and everything is fine.
  3. Rename MyEnums.ts to MyEnums.d.ts
  4. Change the code above to:

  import { MyEnums } from '@/MyEnums.d';

  interface MyIf {
    enums: MyEnums,
    name: string,
  }

  let p0: MyIf = {
    enums: MyEnums.C0,
    name: 'My name',
  }

  1. Run ‘npm run serve’, and you get the error:
  Using 1 worker with 2048MB memory limit
   94% after seal

   ERROR  Failed to compile with 1 errors                                                                                                                         5:46:44 PM

   error  in ./src/MyEnums.d.ts

  Module build failed (from ./node_modules/ts-loader/index.js):
  Error: Debug Failure. Output generation failed
      at Object.transpileModule (/home/user/temp/ts/test/node_modules/typescript/lib/typescript.js:100526:29)
      at getTranspilationEmit (/home/user/temp/ts/test/node_modules/ts-loader/dist/index.js:231:74)
      at successLoader (/home/user/temp/ts/test/node_modules/ts-loader/dist/index.js:33:11)
      at Object.loader (/home/user/temp/ts/test/node_modules/ts-loader/dist/index.js:21:12)

   @ ./src/main.ts 10:0-38 12:9-16
   @ multi (webpack)-dev-server/client?http://192.168.1.48:8081/sockjs-node (webpack)/hot/dev-server.js ./src/main.ts

  Type checking in progress...
  No type errors found
  Version: typescript 3.0.1
  Time: 1984ms

  1. Even though you get No type errors found, when you browse to the address http://localhost:8081, you get the report: URIError: Failed to decode param '/%3C%=%20BASE_URL%20%%3Efavicon.ico' ..., and a blank web page.

What is expected?

No error when using typescript definition files with solution

What is actually happening?

The build tools are complaining about missing dependency, or when using more specific path (so that I make sure the path ends in .ts) I get ‘Output generation failed’.


I run into the issue when building my solution, and after pinning it down to my enums, I realized it has something to do with the naming of the definition files ending in .d.ts and not in .ts.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 16
  • Comments: 18 (2 by maintainers)

Most upvoted comments

I have run into the same problem. Let me add what I found:

Problem appears only if you have some enums in your .d.ts file. It happens because enum is not only a type information that can be stripped, but it has some run-time information (I mean enum values).

I run several tests for simple TS code with babel@7 transpilation without webpack. And I think I found a reason of the issue.

  1. babel transpile enums.d.ts into enums.d.js
  2. in TS code, if you use enum only for typing (like import { SomeEnum } from './enums'; const value: SomeEnum = 2;) then transpiled JS does not have a reference to enum, because babel just strip it. And this case causes no errors
  3. however if you use enum values then transpiled JS has import
// TS
import { SomeEnum  } from './enums'; 
const value = SomeEnum.Qwe;

// Transpiled JS
var _models = require("./enums");
const value = _models.SomeEnum.q;

Now it is obvious that JS expects enums.js file, but we have only enums.d.js. And here it fails.

Well, the core issue is not vue-cli, but I’m not sure where we should report it

The approach I indicated above only works for development, to fix it in both production and development use:

module.exports = {
    chainWebpack: config => {
        const rule = config.module.rule('ts');

        rule.uses.delete('thread-loader');
        rule.use('ts-loader')
            .loader('ts-loader')
            .tap(options => {
                options.transpileOnly = false;
                options.happyPackMode = false;

                return options;
            });
    },
};

@OzairP What do you mean that one of your modules doesn’t transpile TS, isn’t webpack doing the transpilation? In any case, a new app created with the CLI will suffer this problem, so this fixes it for the time being.

@ericdfields I’ve ended up with using string unions instead of enums.

type Direction = 'up' | 'down' | 'left' | 'right'
///
function move(d: Direction) { /* some code */ }
///
move('up')
move('left')
move('dawn')

For me, code looks cleaner. And TS still gets your back with Argument of type '"dawn"' is not assignable to parameter of type 'Direction' check. Auto-completion works too. Looks like a great solution.

You can’t export any actual JavaScript code from declaration files (*.d.ts), because TypeScript removes them from the generated output. Here is a playground demo that illustrates what enums are compiled into.

More info here: https://lukasbehal.com/2017-05-22-enums-in-declaration-files/

I’ve seen this a few times. I think the right solution (given recent enough typescript, I’m using 4.1.3) is import type {Prop} from 'vue/types/options' rather than import {Prop} from 'vue/types/options', i.e. use import type when you’re only importing types. YMMV but it seems to help for me.

I’m encountering this with a codemirror embed in my app. Is there are proper solution at this point?