Vue: Cannot import from a typescript Vue component into another typescript Vue component

Created on 27 Mar 2017  ·  33Comments  ·  Source: vuejs/vue

Version

2.2.6

Reproduction link

https://github.com/borislitvak/vue-from-vue-question

Steps to reproduce

  1. clone repository
  2. npm run build

I've asked on stackoverflow and vue forum, no answer for several days. I am new to client side development.

What is expected?

I can import the MyTable.vue into App.vue.
Both components are writting in Typescript.

NOTE: I can import the TS vue component into another TS file, i.e., App.vue into example.ts.

What is actually happening?

During webpack build:

ERROR in ....\App.vue.ts
(20,24): error TS2307: Cannot find module './MyTable.vue'.


https://forum.vuejs.org/t/how-can-i-view-vue-loader-logs-and-generated-files/8350
http://stackoverflow.com/questions/42945415/import-vue-module-from-another-vue-module-in-typescript

Most helpful comment

This is because you don't have declarations of .vue files, then the typescript compiler cannot load them. You need to declare general declaration of .vue file in your project or generating each .vue file declaration by using vuetype

All 33 comments

This is because you don't have declarations of .vue files, then the typescript compiler cannot load them. You need to declare general declaration of .vue file in your project or generating each .vue file declaration by using vuetype

I cannot thank you enought for your answer, @ktsn ! You've made my day!

Without knowing the above, how would you approach debugging this problem? Do you 'node debug webpack'? If not, how do you know where the problem is? After all, you don't see the generated .d.ts file nor there are any webpack/vue-loader logs.

Thank you,
Boris

Just see the compiler error log. Cannot find module means the TS compiler cannot find the typescript file or its declaration.
FYI: https://www.typescriptlang.org/docs/handbook/modules.html

Happy someone else had the same question. Thank you!

THANK YOU !!

Oh! Why this isn't added into official doc?

I can't seem to get this thing working without vuetype.

Is using vuetype mandatory?

I had almost the same problem, but the above only solved it within Visual Studio Code. When running the development server I got the following error:

Module build failed: Error: Could not find file: '/src/sections/search-result/search-result.vue'.

I solved it by changing the webpack ts-loader config from:

      {
        test: /\.tsx?$/,
        loader: "ts-loader"
      }

to

      {
        test: /\.tsx?$/,
        loader: "ts-loader",
        options: {
          appendTsSuffixTo: [/\.vue$/]
        }
      }

like they do in the upcoming typescript template for vue-cli.

@ktsn Including the sfc.d.ts file allows me to import .vue modules in my typescript files, but it seems to conflict with the Vetur plugin. In my .vue components, the path / file checking for imports is completely disabled when I use the .d.ts file! Also, changes in .vue files are not reflected in autocomplete anymore.

index.ts

import App from './components/app.vue'  // only works with the sfc.d.ts file

app.vue

<script lang="ts">
    import Vue from 'vue'
    import Card from "./notexist/card.vue"  // only works WITHOUT the sfc.d.ts file!
</script>

Including vue-shims.d.ts in the files property of tsconfig.json fixed the issue for me:

"files": [
        "./static/types/vue-shims.d.ts"
]

u can import component without use suffix .vue

  • Home.vue
<template>
  <div class="home">
     home ...
  </div>
</template>
<script lang="ts" src="./Home.ts">
</script>
  • Home.ts
import { Vue } from 'vue-property-decorator';
@Component
export default class Home extends Vue {}
  • App.vue
// doesn't work
// import Home from './views/Home.vue';

// well done 
import Home from './views/Home'

@ktsn I previously used the general vue declaration ("vue-shim") you linked to, but I'm facing a problem now that I'm trying to augment the Vue type with a custom property on the prototype:

In order for VS Code to recognize the plugin, I have to declare a module for 'vue/types/vue':

import Vue from 'vue'
import { MomentTimezone } from 'moment-timezone'

declare module 'vue/types/vue' {
  export interface Vue {
    $moment: MomentTimezone
  }
}

This conflicts with the vue-shim, which declares a module for '*.vue', so now I have TS support for my $moment method on the Vue prototype, but tslint cannot deal with my path aliases for importing vue SFCs and gives me lots of TS2307 warnings in the terminal at compile time (even though the app compiles fine). How can I keep support for path aliases but also augment the Vue type for extending the Vue prototype?

@TychoCRD I'm also running into this issue, I was wondering if you ended up solving it?

My last resort here is to use @ts-ignore to get rid of the compile time errors.

@ktsn Thank you. But it is not resolve. Then i try resolve as TypeScript-Vue-Starter,

// src/vue-shims.d.ts

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

it resolve.

@borislitvak @ktsn @korziee In my case , when I try to import some vue files into the jest files written in ts format, vs code hint that I got an error in forms [ts] cannot find module... 2307. I think that it must be a problem for vs code to resolve the module path, so I include all the paths that typescript should treat that files, in tsconfig.json, just like this:

{
  "include": [
    "src/**/*.ts",
    "src/**/*.vue",
    "test/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ],
  "files": [
    "ts-custom.d.ts"
  ],
  "types": [
    "jest"
  ],
  "compilerOptions": {
    "outDir": "./dist/",
    "target": "es5",
    "module": "esnext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "noImplicitReturns": true,
    "allowJs": false,
    "sourceMap": true,
    "pretty": true,
    "removeComments": true
  }
}

and finally, vs code feel so happy. :laugh:

Hey @ktsn your link "https://github.com/vuejs/vue-class-component/blob/master/example/sfc.d.ts" is broken. I can't find its equivalent through google.

I have this shim that I use in my projects:

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

But this obviously doesn't work for named exports. vuetype doesn't appear to work for them either. I'd like to find out if there's a way to use Vue and TypeScript with named exports because they cut down on potential typos.

@beetaa Many thanks for saving my time. For those unfamiliar like me, important elements are:

  1. Create a ts-shim.d.ts

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

    I copied from @beetaa template's

  2. Update tsconfig.json. I am using Nuxt so I include everthing

    {
      "include": ["**/*.ts", "**/*.vue"],
      "exclude": ["node_modules"],
      "files": ["ts-shim.d.ts"]
    }
    

    Inspired by the same repo

  3. For reference, as my case was also in testing file, my jest.config.js is:

    module.exports = {
      moduleNameMapper: {
        '^@/(.*)$': '<rootDir>/$1',
        '^~/(.*)$': '<rootDir>/$1'
      },
      transform: {
        '^.+\\.ts?$': 'ts-jest',
        '.*\\.(vue)$': 'vue-jest'
      },
      moduleFileExtensions: ['ts', 'js', 'vue', 'json']
    };
    

It is implemented here

The link provided in the upvoted comment is broken.

What is the solution to this problem as of Jun, 2019?

As of today, vuetype has not been updated since February 2018 and won't work with non-class-based Vue component declaration.

Seems like we still don't have a way to directly import .vue files as TypeScript classes and infer their type signature

Then the obvious question is: Why is this still closed then?
Is there a new, open issue?
Or does "it technically works but your IDE won't notice" count as a valid argument?

@skovmand Your solution worked for me as well, but i haven't notice it untill I disabled the "Vetur" extension in Visual Studio Code. It keeps the red error underline when importing Vue components without .vue suffix despite everithing worked fine.

The shims-vue.d.ts solution, as described by @Al-un is already implemented in the Vue CLI Typescript template, but I'm still getting this error.

Ugh forget that. I just forgot to include the .vue extension:

import Foo from 'foo.vue'; // Works
import Foo from 'foo';     // Does not work!

I also have to include the .vue extension when importing components or I get the same errror.

I am using

"@vue/cli-plugin-babel": "^4.1.2", "@vue/cli-plugin-pwa": "^4.1.2", "@vue/cli-plugin-typescript": "^4.1.2", "@vue/cli-service": "^4.1.2",

It seems there is something missing still. I have tried using shims-vue.d.ts in the files section with no results.. Any help would be appreciated. :)

@NavidMitchell
I have same issue.

Does not work:

// index.ts   
import Sample from 'components/Sample'
// App.vue   


md5-e41499c6556c0fed13588409737054b4





md5-dd2b739d451837fbb022e5484eab19b3



// index.ts   
const Sample = require('components/Sample')



md5-a0ab31bd4d235a42a22a7b6d94a76531



// index.ts   
import Sample from 'components/Sample.vue'



md5-a0ab31bd4d235a42a22a7b6d94a76531



// index.js   
import Sample from 'components/Sample'



md5-a0ab31bd4d235a42a22a7b6d94a76531



// App.vue   


md5-a043d69c086d26611c3884dc6ef772fe





md5-a0ab31bd4d235a42a22a7b6d94a76531



// App.vue   


md5-e1b52cd70a17817d8bd2c180b7f85614





md5-6cc42e563bba2a478166fb1098a765d6




            {
                "test": "/\\.ts$/",
                "use": [
// ....
                        "options": {
                            "appendTsSuffixTo": [
                                "/\\.vue$/"
                            ]
                        }
                  ]
            }

I followed the upvoted comment but it didn't work.
i checked ts-loader version was 4.5.1. After I downgraded it to 4.1.0 it worked.

Looks like there was a breaking change, but the semver ^4.1.0 will not work.
For time being change it to exact match 4.1.0

If declare module "*.vue" not working it is because the declaration file contain some code that not acceptable by the ts.

I gave up on generating proper .d.ts files for .vue files (instead of using the shim) and just put everything that I needed to import from the .vue file into an actual .ts file. I.e. instead of this, which does not work:

// foo.vue

export enum Stuff {
  ...
}

@Component
export default class Foo extends Vue {
   public baz() {
   }
}
// bar.vue
import { Stuff } from "./foo.vue"
// Does not work by default because it is using the shim which does not know about `Stuff`

I do this:

// stuff.ts
export enum Stuff {
  ...
}
// foo.vue
import { Stuff } from "./stuff"

@Component
export default class Foo extends Vue {
   public baz() {
   }
}
// bar.vue
import { Stuff } from "./stuff"

Definitely easier than faffing around with .d.ts files. The only downside is that the shim makes every .vue file act as if it is exporting a Vue object. So if you do this:

import Foo from "./foo.vue"

It does compile but Typescript thinks that Foo is just an alias for Vue, so if you try to call Foo.baz() you'll get an error.

My ultimate solution is to switch to React which is simply much much better at integrating with Typescript (it also type checks templates which is a pretty huge flaw in Vue).

@Timmmm
https://github.com/quasarframework/quasar-testing/issues/48#issuecomment-507763139
Here, at Demo component section, I explain how to use a Double File Component fashion to make inference work

import Foo from 'foo.vue'; // Works
import Foo from 'foo'; // Does not work!

This answer is downvoted, but for some reason only this works. Though I do not undrstand why...

My ultimate solution is to switch to React which is simply much much better at integrating with Typescript (it also type checks templates which is a pretty huge flaw in Vue).

Hi @Timmmm, the .vue files are only a suggestion from Vue, as the lib itself is not entirely opinionated on how you render the templates and how you inject or inline the CSS. You can also use Vue with separate templates, even in JSX, just like React. It can be considered non-standard but it works (in fact, I prefer it like that, .vue files tend to get very messy). Switching to React is, though, an understandable way to go if you're really into TS.

u can import component without use suffix .vue

  • Home.vue
<template>
  <div class="home">
     home ...
  </div>
</template>
<script lang="ts" src="./Home.ts">
</script>
  • Home.ts
import { Vue } from 'vue-property-decorator';
@Component
export default class Home extends Vue {}
  • App.vue
// doesn't work
// import Home from './views/Home.vue';

// well done 
import Home from './views/Home'

If I want to also separate template, is there any workaround?

Well, you can move the style part into a standalone file and reference it as you do for the script part. In that way you only get the template part in the .vue file

Was this page helpful?
0 / 5 - 0 ratings