vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.71k stars 8.33k forks source link

<script setup>: Prop Member "Args.Post" is conflicting with "Post" import from PostDef.ts #4758

Closed phasetri closed 3 years ago

phasetri commented 3 years ago

Version

3.2.19

Reproduction link

sfc.vuejs.org/

Steps to reproduce

yarn global add @vue/cli
vue create my_project

Select these options when prompted:

? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors
? Choose a version of Vue.js that you want to start the project with 3.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
cd my_project
cd src/components
touch PostDef.ts
touch PostFc.vue

Content of PostDef.ts:

export interface Post {
  Message: string; 
}

Content of PostFc.vue:

<script setup lang="ts">

import {
  Post,
} from "./PostDef";

interface Props {
  Args: {Post: Post};
}
const props = withDefaults(defineProps<Props>(), {});
</script> 

<template>
  {{Args.Post}}
</template>

Within the auto-generated HelloWorld.vue, add a PostFc instance anywhere on the page

<script lang="ts">
import { defineComponent } from 'vue';
import PostFcVue from './PostFc.vue';

export default defineComponent({
  name: 'HelloWorld',
  props: {
    msg: String,
  },
  components: {
    PostFc: PostFcVue
  }
});
</script>

<template>
      ...
      ...
      ...
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
    </ul>
    <PostFc :Args="{Post: {Message: 'Hello World!!!'}}"></PostFc>
  </div>
</template>

Then run the app:

yarn 
yarn serve

What is expected?

No warnings should be reported when yarn serve finishes compiling the app.

What is actually happening?

When yarn serve finishes compiling the app, it will report a warning that PostDef.ts does not have a reference to Post:

warning  in ./src/components/PostFc.vue?vue&type=script&setup=true&lang=ts

"export 'Post' was not found in './PostDef'

Note that the warning is not visible in the reproduction link; you have to reproduce it on your local machine.


I was able to reproduce the same problem by creating a Vite project instead of Vue-CLI project.

The problem is particularly serious in Vite as the warning gets reported on the browser console, and cause the whole HelloWorld page to not load at all.

You can quickly make the warning go away by modifying the template in PostFc.vue such that {{Args.Post}} does not reference Post at all --- for example: {{Args}}

phasetri commented 3 years ago

I think I found the reason why:

https://v3.vuejs.org/api/sfc-script-setup.html#typescript-only-features

Currently complex types and type imports from other files are not supported. It is theoretically possible to support type imports in the future.

Is there some other way that I can use to specify complex types for my prop members?

ygj6 commented 3 years ago

Duplicate of #4294

ygj6 commented 3 years ago

Is there some other way that I can use to specify complex types for my prop members?

You could try to use like this:

<script lang="ts">
 export interface Post {
  Message: string; 
}
</script>   
<script setup lang="ts">

interface Props {
  Args: {Post: Post};
}
const props = withDefaults(defineProps<Props>(), {});
</script> 

<template>
  {{Args.Post}}
</template>
phasetri commented 3 years ago

That works.

Interesting, I also found that you can create the same warning using this:

<script lang="ts">
import {
  Post,
} from "./PostDef";
</script>

<script setup lang="ts">
interface Props {
  Args: {Post: any};
}
const props = withDefaults(defineProps<Props>(), {});
</script> 

<template>
  {{Args.Post}}
</template>

Either way, I prefer putting my interfaces into a separate file; I'll try working around the problem in the meantime.

krytes commented 2 years ago

import { Props } from "./useHooks"; interface NewProps extends Props = {}; const props = defineProps<NewProps>();