vuejs / vue-cli

🛠️ webpack-based tooling for Vue.js Development
https://cli.vuejs.org/
MIT License
29.75k stars 6.33k forks source link

Can't import component's exported types in a test #6924

Open huuff opened 2 years ago

huuff commented 2 years ago

Version

5.0.0-rc.1

Reproduction link

github.com

Environment info

Environment Info:

  System:
    OS: Linux 5.10 NixOS 21.11 (Porcupine) 21.11 (Porcupine)
    CPU: (4) x64 Intel(R) Core(TM) i5-4460  CPU @ 3.20GHz
  Binaries:
    Node: 16.3.0 - /nix/store/dpn8hvlq7v703kz3x3npx6522x89kb57-nodejs-16.3.0/bin/node
    Yarn: Not Found
    npm: 7.18.1 - /nix/store/gjb90hapc9qz532c52gslv6p98nkhwj8-node_npm-7.18.1/bin/npm
  Browsers:
    Chrome: Not Found
    Firefox: 93.0
  npmPackages:
    @vue/babel-helper-vue-jsx-merge-props:  1.2.1
    @vue/babel-helper-vue-transform-on:  1.0.2
    @vue/babel-plugin-jsx:  1.1.1
    @vue/babel-plugin-transform-vue-jsx:  1.2.1
    @vue/babel-preset-app:  5.0.0-rc.1
    @vue/babel-preset-jsx:  1.2.4
    @vue/babel-sugar-composition-api-inject-h:  1.2.1
    @vue/babel-sugar-composition-api-render-instance:  1.2.4
    @vue/babel-sugar-functional-vue:  1.2.2
    @vue/babel-sugar-inject-h:  1.2.2
    @vue/babel-sugar-v-model:  1.2.3
    @vue/babel-sugar-v-on:  1.2.3
    @vue/cli-overlay:  5.0.0-rc.1
    @vue/cli-plugin-babel: ~5.0.0-rc.1 => 5.0.0-rc.1
    @vue/cli-plugin-eslint: ~5.0.0-rc.1 => 5.0.0-rc.1
    @vue/cli-plugin-router:  5.0.0-rc.1
    @vue/cli-plugin-typescript: ~5.0.0-rc.1 => 5.0.0-rc.1
    @vue/cli-plugin-unit-jest: ~5.0.0-rc.1 => 5.0.0-rc.1
    @vue/cli-plugin-vuex:  5.0.0-rc.1
    @vue/cli-service: ~5.0.0-rc.1 => 5.0.0-rc.1
    @vue/cli-shared-utils:  5.0.0-rc.1
    @vue/compiler-core:  3.2.26
    @vue/compiler-dom:  3.2.26
    @vue/compiler-sfc:  3.2.26
    @vue/compiler-ssr:  3.2.26
    @vue/component-compiler-utils:  3.3.0
    @vue/eslint-config-typescript: ^9.1.0 => 9.1.0
    @vue/reactivity:  3.2.26
    @vue/reactivity-transform:  3.2.26
    @vue/runtime-core:  3.2.26
    @vue/runtime-dom:  3.2.26
    @vue/server-renderer:  3.2.26
    @vue/shared:  3.2.26
    @vue/test-utils: ^2.0.0-0 => 2.0.0-rc.18
    @vue/vue3-jest: ^27.0.0-alpha.1 => 27.0.0-alpha.4
    @vue/web-component-wrapper:  1.3.0
    eslint-plugin-vue: ^8.0.3 => 8.2.0
    jest-serializer-vue:  2.0.2
    typescript: ~4.1.5 => 4.1.6
    vue: ^3.2.13 => 3.2.26
    vue-eslint-parser:  8.0.1
    vue-hot-reload-api:  2.3.4
    vue-loader:  16.8.3 (15.9.8)
    vue-style-loader:  4.1.3
    vue-template-es2015-compiler:  1.9.1
  npmGlobalPackages:
    @vue/cli: 5.0.0-rc.1

Steps to reproduce

Write a component that exports a type

<template>
<slot></slot>
</template>

<script setup lang="ts">

export interface TestProps {
  input: string;
}

const props = defineProps<TestProps>();

</script>

Then try to import it in a test

import { mount } from "@vue/test-utils";
import TestComponent, { TestProps } from "./TestComponent.vue";

describe("TestComponent.vue", () => {
  test("should compile", () => {
    const wrapper = mount(TestComponent, {
      props: { input: "test" },
    })
  })
});

See how it fails to compile with the following error:

    tests/unit/TestComponent.spec.ts:2:25 - error TS2614: Module '"*.vue"' has no exported member 'TestProps'. Did you mean to use 'import TestProps from "*.vue"' instead?

    2 import TestComponent, { TestProps } from "./TestComponent.vue";

What is expected?

The code compiles

What is actually happening?

It fails with

    tests/unit/TestComponent.spec.ts:2:25 - error TS2614: Module '"*.vue"' has no exported member 'TestProps'. Did you mean to use 'import TestProps from "*.vue"' instead?

    2 import TestComponent, { TestProps } from "./TestComponent.vue";

Note that these types of exports and imports work fine when running npm run serve

screetBloom commented 2 years ago

If you want to import interface, it is recommended that you should write it in a separate .ts file

And then import it in a test

// ./types/index.ts
export interface TestProps {
  input: string;
}
<template></template>

<script setup lang="ts">
import { TestProps } from './types'

const props = defineProps<TestProps>();

</script>


Then import them in a test

import { mount } from "@vue/test-utils";
import TestComponent from "./TestComponent.vue";
import { TestProps } from './types'

describe("TestComponent.vue", () => {
  test("should compile", () => {
    const wrapper = mount(TestComponent, {
      props: { input: "test" },
    })
  })
});
huuff commented 2 years ago

Thanks for your answer. I tried this and got

    [@vue/compiler-sfc] type argument passed to defineProps() must be a literal type, or a reference to an interface or literal type.

Are you sure this is possible? I though this open issue prevented it. I've uploaded a branch external_props to my MCVE with your suggested changes and I'd be really grateful if you did a PR with whatever changes necessary to make it work

maersk96 commented 2 years ago

As of now this is not possible. The interface has to be in the same file. See Syntax Limitations in the vue documentation.