vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
208k stars 33.69k forks source link

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

Closed borislitvak closed 7 years ago

borislitvak commented 7 years ago

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 commented 7 years ago

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

borislitvak commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

Happy someone else had the same question. Thank you!

davidm-public commented 7 years ago

THANK YOU !!

gluons commented 7 years ago

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

jamelt commented 7 years ago

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

Is using vuetype mandatory?

skovmand commented 7 years ago

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 commented 7 years ago

@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 commented 6 years ago

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 commented 6 years ago

u can import component without use suffix .vue

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

TychoCRD commented 6 years ago

@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 commented 5 years ago

@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 commented 5 years ago

@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 commented 5 years ago

@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 commented 5 years ago

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 commented 5 years ago

@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 commented 5 years ago

The link provided in the upvoted comment is broken.

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

IlCallo commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

@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 commented 5 years ago

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 commented 5 years ago

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 commented 4 years ago

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 commented 4 years ago

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

MaheshSasidharan commented 4 years ago

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 commented 4 years ago

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

Timmmm commented 4 years ago

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 commented 4 years ago

@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

bravik commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

@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 commented 3 years ago

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

Moghul commented 3 years ago

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;
}
phil294 commented 3 years ago

@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 commented 2 years ago

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?