Skip to content

Interface export not being hoisted in the presence of <script> and macros #5485

Open
@andylizi

Description

@andylizi

Vue - Official extension or vue-tsc version

3.0.1

VSCode version

1.101.2

Vue version

3.5.17

TypeScript version

5.8.3

System Info

System: OS: macOS 15.5 Shell: 4.0.2 - /opt/homebrew/bin/fish Binaries: Node: 20.5.0 Yarn: 1.22.22 npm: 9.8.0 pnpm: 10.11.0 Browsers: Chrome: 138.0.7204.93 Safari: 18.5

Steps to reproduce

  1. pnpm create vue@latest
  2. Open src/components/HelloWorld.vue and put in
    <script lang="ts"></script> <script setup lang="ts"> defineOptions({});  export interface MyProps {  msg: string; }  const { msg } = defineProps<MyProps>() </script>

What is expected?

No errors, since 'interface hoisting for defineProps' is a supported feature as per #2421.

Expected codegen
/// <reference types="../../node_modules/.vue-global-types/vue_3.5_0_0_0.d.ts" /> export interface MyProps { msg: string; } debugger/* PartiallyEnd: #3632/both.vue */ export default await (async () => { defineOptions({}); type __VLS_Props = MyProps; const { msg } = defineProps<__VLS_Props>() debugger/* PartiallyEnd: #3632/scriptSetup.vue */ // @ts-ignore declare const { defineProps, defineSlots, defineEmits, defineExpose, defineModel, defineOptions, withDefaults, }: typeof import('vue'); type __VLS_PublicProps = __VLS_Props; const __VLS_ctx = {} as InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>; let __VLS_elements!: __VLS_IntrinsicElements; type __VLS_LocalComponents = & typeof __VLS_ctx; let __VLS_components!: __VLS_LocalComponents & __VLS_GlobalComponents; type __VLS_LocalDirectives = & typeof __VLS_ctx; let __VLS_directives!: __VLS_LocalDirectives & __VLS_GlobalDirectives; type __VLS_Slots = {}; type __VLS_InheritedAttrs = {}; type __VLS_TemplateRefs = {}; type __VLS_RootEl = any; const __VLS_self = (await import('vue')).defineComponent({ setup() { return { }; }, __typeProps: {} as __VLS_PublicProps, }); return (await import('vue')).defineComponent({ setup() { return { }; }, __typeProps: {} as __VLS_PublicProps, }); })();/* PartiallyEnd: #4569/main.vue */ type __VLS_TypePropsToOption<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? { type: import('vue').PropType<Required<T>[K]> } : { type: import('vue').PropType<T[K]>, required: true } };

What is actually happening?

TS1184 Modifiers cannot appear here on the line export interface MyProps {.

Actual (broken) codegen
/// <reference types="../../node_modules/.vue-global-types/vue_3.5_0_0_0.d.ts" /> debugger/* PartiallyEnd: #3632/both.vue */ export default await (async () => { defineOptions({}); export interface MyProps { msg: string; } type __VLS_Props = MyProps; const { msg } = defineProps<__VLS_Props>() debugger/* PartiallyEnd: #3632/scriptSetup.vue */ // @ts-ignore declare const { defineProps, defineSlots, defineEmits, defineExpose, defineModel, defineOptions, withDefaults, }: typeof import('vue'); type __VLS_PublicProps = __VLS_Props; const __VLS_ctx = {} as InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>; let __VLS_elements!: __VLS_IntrinsicElements; type __VLS_LocalComponents = & typeof __VLS_ctx; let __VLS_components!: __VLS_LocalComponents & __VLS_GlobalComponents; type __VLS_LocalDirectives = & typeof __VLS_ctx; let __VLS_directives!: __VLS_LocalDirectives & __VLS_GlobalDirectives; type __VLS_Slots = {}; type __VLS_InheritedAttrs = {}; type __VLS_TemplateRefs = {}; type __VLS_RootEl = any; const __VLS_self = (await import('vue')).defineComponent({ setup() { return { }; }, __typeProps: {} as __VLS_PublicProps, }); return (await import('vue')).defineComponent({ setup() { return { }; }, __typeProps: {} as __VLS_PublicProps, }); })();/* PartiallyEnd: #4569/main.vue */ type __VLS_TypePropsToOption<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? { type: import('vue').PropType<Required<T>[K]> } : { type: import('vue').PropType<T[K]>, required: true } };

Any additional comments?

The error only happens when three things are true:

  1. There is a <script lang="ts"> tag (empty ones are fine) along with <script setup lang="ts">.
    • Removing the tag will fix the error.
  2. There is an export interface or export type inside <script setup lang="ts>.
    • Also true for export const, but I'm not sure that's supported in <script setup> anyway.
  3. There is a compiler macro that appears before the export item.
    • Any macro seems to reproduce: defineOptions, defineEmits, defineExpose, etc.
    • The order is important. The error is gone when I move defineOptions({}) after the interface export.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions