2

I have a small .js file using Vue that I want to be type-checked with the TypeScript compiler:

function main() {
    new Vue({
        el: 'ts-message',
        template: '<div>Hello</div>',
    });
}

If I try to typecheck it with tsc, the compiler complains it cannot find the declaration for Vue even though I have the vue npm package installed:

$ tsc --allowJs --checkJs --noEmit src/main.js 
src/main.js:6:9 - error TS2304: Cannot find name 'Vue'.

6     new Vue({
          ~~~

How do I tell the TypeScript compiler to auto-detect the Vue global object or to import it explicitly in the JS file?

Other things I tried

If this main.js file is renamed to main.ts and I add the following line to the top, then the TypeScript compiler succeeds:

import Vue from "vue";

Unfortunately I need to typecheck JavaScript files specifically and I cannot add such a line to the top of a JavaScript file, since browsers do not recognize that kind of import syntax.

2
  • You can do that with a typing file containing global augmentation. Commented Jun 29, 2019 at 21:42
  • @unional I tried a few variations on the following but got various errors: export {}; declare global { import Vue from "vue"; export default Vue; } Commented Jun 29, 2019 at 22:11

4 Answers 4

1

Try this:

  1. create a typings/vue.d.ts
// typings/vue.d.ts
import Vue from 'vue'

export as namespace Vue
  1. Include the typings folder in your jsconfig.json:
// jsconfig.json
{
  "include": ["typings"]
}

I have not use Vue.js myself. My assumption is that its typings does not expose Vue globally.

The file above gets the type from vue and expose it as a namespace.

Sign up to request clarification or add additional context in comments.

5 Comments

With the additional vue.d.ts, I get a compiler error on main.js, pointing at the "new Vue({" line: error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. -- I suspect that Vue when exported as a "namespace" cannot be used as a constructor anymore.
Yes. That make sense. I was thinking about the types. You also need to declare the variable. Let me check.
Try adding declare const Vue: typeof VueExport in that file. and rename import to import VueModule from 'vue.
You probably also need esModuleInterop in your config.
I got the same compiler error with those modifications, however declare const Vue: typeof VueExport was enough of a hint that I was able to derive a provisional answer! stackoverflow.com/a/56822240/604063
0

I think you may need to declare the Vue.js via a vue.shims.d.ts file in the main source folder(src folder for example).

Something like this:

declare module "*.vue" {
    import Vue from "vue";
    export default Vue;
}

1 Comment

That shims file appears to modify how tsc interprets *.vue files, but there are no *.vue files in this example. I tried to modify the first line to say declare module "*.js" { instead but that didn't work either.
0

For vue <= 2.5.17

Create a src/vue.shims.d.ts file with the following content:

import VueConstructor from 'vue';
declare global {
    const Vue: typeof VueConstructor;
}

Then compile it along with the original src/main.js using:

$ tsc --allowJs --checkJs --noEmit src/main.js src/vue.shims.d.ts

It works! 🎉

For vue 2.5.18 thru 2.6.10

Open node_modules/vue/types/index.d.ts and comment out the following line:

export as namespace Vue;

replacing it with:

//export as namespace Vue;  // interferes with vue.shims.d.ts

Now you can use the vue.shims.d.ts file mentioned earlier in this answer.

Caution: Modifying a dependency in place is quite a brittle approach. If possible I'd recommend upgrading Vue instead.

For vue > 2.6.10

The development version of Vue has a closed issue and merged PR that makes it possible to use Vue as a global from within a script so long as you explicitly include Vue's types definitions.

Install a development version of Vue:

$ npm install 'git+ssh://[email protected]/vuejs/vue.git#ab50e8e1da2f4f944af683252481728485fedf16'

Now compile the JS script along with the vue/types/index.d.ts file.

$ tsc --allowJs --checkJs --noEmit src/main.js node_modules/vue/types/index.d.ts

3 Comments

It seems this solution only works for [email protected] and below. In particular this solution does not work for 2.5.18 or the latest 2.6.10. -- 2.5.18 introduced the line "export as namespace Vue;" in its top-level index.d.ts. I'm going to investigate further...
Apparently in [email protected] the vue/types/index.d.ts was modified to add the line export as namespace Vue;. If I remove this line then the shim presented in this answer works again. Unfortunately modifying a dependency like Vue directly is brittle so I'm still looking for a better solution.
In that case, try to do declare module 'vue' {...} it may work.
0

How do I tell the TypeScript compiler to auto-detect the Vue global object or to import it explicitly in the JS file?

You could do this with a module bundler that invokes the TypeScript compiler, or use a CDN. No manual typings (*.d.ts) are necessary in your case.

Module Bundler

In order to use npm packages in the browser, you need a module bundler (such as Webpack, Rollup, or Parcel) to create a script that includes those packages.

I highly recommend using Vue CLI to automatically scaffold a TypeScript project, which includes Webpack. A few advantages of this generated project:

  • allows using import (or require) in your scripts even when targeting browsers, as the build output would automatically bundle the imported packages
  • minimizes JavaScript fatigue by using sensible defaults that are easily configurable
  • provides IDE support (e.g., via Vetur in Visual Studio Code) that includes automatic type-checking as you code

CDN

If you prefer not to use a module bundler, you could import the third-party scripts from a CDN into the global scope with a <script> tag before your own script runs. For instance, to import Vue and Vue-Router from unpkg, your index.html could contain this:

<script src="https://unpkg.com/[email protected]"></script>
<script src="https://unpkg.com/[email protected]"></script>

<script src="./main.js"></script>

new Vue({
  el: '#app',
  data: () => ({
    message: 'Hello Vue.js!',
  }),
})
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">
  <p>{{ message }}</p>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.