Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot import from a typescript Vue component into another typescript Vue component #5298

Closed
borislitvak opened this issue Mar 27, 2017 · 40 comments

Comments

@borislitvak
Copy link

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

@ktsn
Copy link
Member

ktsn commented Mar 28, 2017

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

@ktsn ktsn closed this as completed Mar 28, 2017
@borislitvak
Copy link
Author

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

@ktsn
Copy link
Member

ktsn commented Mar 28, 2017

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

@daple
Copy link

daple commented Mar 31, 2017

Happy someone else had the same question. Thank you!

@davidm-public
Copy link

THANK YOU !!

@gluons
Copy link

gluons commented Sep 19, 2017

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

@jamelt
Copy link

jamelt commented Oct 4, 2017

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

Is using vuetype mandatory?

@skovmand
Copy link

skovmand commented Oct 27, 2017

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.

@KokoDoko
Copy link

KokoDoko commented Nov 10, 2017

@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>

@realmhamdy
Copy link

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

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

@lin-123
Copy link

lin-123 commented Jul 4, 2018

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'

@TychoCRD
Copy link

@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?

@korziee
Copy link

korziee commented Dec 17, 2018

@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.

@zeybar
Copy link

zeybar commented Jan 10, 2019

@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.

@beetaa
Copy link

beetaa commented Jan 11, 2019

@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:

@MattiasMartens
Copy link

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.

@Al-un
Copy link

Al-un commented Feb 15, 2019

@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

@komali2
Copy link

komali2 commented Jun 3, 2019

The link provided in the upvoted comment is broken.

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

@IlCallo
Copy link

IlCallo commented Jul 8, 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

@MarkL4YG
Copy link

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?

@UstymUkhman
Copy link

UstymUkhman commented Sep 5, 2019

@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.

@Timmmm
Copy link

Timmmm commented Oct 23, 2019

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.

@Timmmm
Copy link

Timmmm commented Oct 23, 2019

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

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

@NavidMitchell
Copy link

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. :)

@l00k
Copy link

l00k commented Mar 24, 2020

@NavidMitchell
I have same issue.

Does not work:

// index.ts   
import Sample from 'components/Sample'
// App.vue   
<script lang="ts">
import Sample from 'components/Sample'
</script>

Does work:

// index.ts   
const Sample = require('components/Sample')
// index.ts   
import Sample from 'components/Sample.vue'
// index.js   
import Sample from 'components/Sample'
// App.vue   
<script lang="ts">
import Sample from 'components/Sample.vue'
</script>
// App.vue   
<script lang="js">
import Sample from 'components/Sample'
</script>

It seems the issue is in ts-loader..

  • project based on @vue/cli:4.2.3
  • shims-vue.d.ts is present
  • webpack is well configured according to previous comments

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

@MaheshSasidharan
Copy link

MaheshSasidharan commented Apr 4, 2020

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

@towry
Copy link

towry commented Apr 9, 2020

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

@Timmmm
Copy link

Timmmm commented Apr 9, 2020

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).

@IlCallo
Copy link

IlCallo commented Apr 9, 2020

@Timmmm
quasarframework/quasar-testing#48 (comment)
Here, at Demo component section, I explain how to use a Double File Component fashion to make inference work

@bravik
Copy link

bravik commented May 22, 2020

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...

@msandrini
Copy link

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.

@TempeBrennan
Copy link

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?

@IlCallo
Copy link

IlCallo commented Sep 6, 2020

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

@ninofiliu
Copy link

ninofiliu commented Jan 16, 2021

For Vue3 (found in @FredKSchott 's snowpack + vue + typescript template)

Declare the type of your *.vue files in /types/shims-vue.d.ts (or wherever you'd prefer)

declare module '*.vue' {
  import { defineComponent } from 'vue';
  const component: ReturnType<typeof defineComponent>;
  export default component;
}

then tell typescript to include it in /tsconfig.json

{
  "include": [
    "types",
    // ...
  ],
  // ...
}

@Anubarak
Copy link

@ninofiliu I did that but I still cannot import Vue components via

import MyComponent from "@/components/MyComponent";

only via

import MyComponent from "@/components/MyComponent.vue";

Is there any other change required?

@ninofiliu
Copy link

@Anubarak well yes, if you write declare module '*.vue' that'll only declare types when you import files that match *.vue, so "@/components/MyComponent.vue" is ok, but not "@/components/MyComponent"

@Anubarak
Copy link

@ninofiliu Thank you very much for your answer. That explains it. Guess I'll just always import them as .vue files then.

@Moghul
Copy link

Moghul commented Jul 5, 2021

What's the reason for the vue shim not to be included in vue's own typescript support? Do I really have to have this 'noise' file in my project that could easily be in the library I'm working with? My webpack build doesn't compile without this thing:

shims-vue.d.ts

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

unglaublicherdude added a commit to unglaublicherdude/complete-vuejs that referenced this issue Oct 15, 2021
@phil294
Copy link

phil294 commented Nov 16, 2021

@ninofiliu I have found that the ...ReturnType<typeof defineComponent> solution can royally mess things up.

To be more specific, when you are using Vue 3 + options api + using a components:{SomeComp} and return a value from any lifecycle method or watch handler that previously has accessed any this value. Debugging this was immensely stupid and time consuming, but I have found the following solution to not bring any of these issues:

declare module '*.vue' {
  import { DefineComponent } from 'vue';
  const component: DefineComponent<{}, {}, any>;
  export default component;
}

This is also the solution taken in the Vue 3 Codesandbox playground and also suggested by Vetur docs.

@AlexVFornazieri
Copy link

AlexVFornazieri commented Jan 9, 2022

Hey everyone,

I tried import a Component class inside a .ts file, a mixin. In .vue's files import occurs normal, no error in VsCode, but import inside a .ts's file the erro show up. Adding a ts-shim file with *.vue declaration, the error gone, but I lose CTRL + (go to) in all .vue imports, even inside .vue's files (that have no errors without ts-shim) :/

Any one have a better solution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests