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

[vue-tsc@^0.36] Invalid declaration when using <script setup> #1459

Closed
bounoable opened this issue Jun 14, 2022 · 3 comments
Closed

[vue-tsc@^0.36] Invalid declaration when using <script setup> #1459

bounoable opened this issue Jun 14, 2022 · 3 comments
Labels
bug Something isn't working

Comments

@bounoable
Copy link

bounoable commented Jun 14, 2022

Starting from v0.36 of vue-tsc, the generated declaration files of SFCs are broken.

Reproduction

I'm using the default project that is scaffolded by create-vite-app, but manually upgraded vue-tsc to the latest version. I also removed the env.d.ts file according to this comment and use vue-tsc --declaration --emitDeclarationOnly to generate the type declarations.

components/HelloWorld.vue

<script lang="ts" setup>
import { ref } from 'vue'

defineProps<{ msg: string }>()

const count = ref(0)
</script>

<template>
  <h1>{{ msg }}</h1>

  <p>
    Recommended IDE setup:
    <a href="https://code.visualstudio.com/" target="_blank">VS Code</a>
    +
    <a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
  </p>

  <p>See <code>README.md</code> for more information.</p>

  <p>
    <a href="https://vitejs.dev/guide/features.html" target="_blank">
      Vite Docs
    </a>
    |
    <a href="https://v3.vuejs.org/" target="_blank">Vue 3 Docs</a>
  </p>

  <button type="button" @click="count++">count is: {{ count }}</button>
  <p>
    Edit
    <code>components/HelloWorld.vue</code> to test hot module replacement.
  </p>
</template>

<style scoped>
a {
  color: #42b983;
}

label {
  margin: 0 0.5em;
  font-weight: bold;
}

code {
  background-color: #eee;
  padding: 2px 4px;
  border-radius: 4px;
  color: #304455;
}
</style>

Output

The generated HelloWorld.vue.d.ts is different between v0.35 and v0.36 of vue-tsc.

v0.35

declare const _default: import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<{
    msg: string;
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
    msg: string;
}>>>, {}>;
export default _default;
declare type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
declare type __VLS_TypePropsToRuntimeProps<T> = {
    [K in keyof T]-?: {} extends Pick<T, K> ? {
        type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
    } : {
        type: import('vue').PropType<T[K]>;
        required: true;
    };
};

v0.36

declare const _default: new () => {
    $: import("vue").ComponentInternalInstance;
    $data: {};
    $props: Partial<{}> & Omit<Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
        msg: string;
    }>>> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>;
    $attrs: {
        [x: string]: unknown;
    };
    $refs: {
        [x: string]: unknown;
    };
    $slots: Readonly<{
        [name: string]: import("vue").Slot | undefined;
    }>;
    $root: import("vue").ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, import("vue").ComponentOptionsBase<any, any, any, any, any, any, any, any, any, {}>> | null;
    $parent: import("vue").ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, import("vue").ComponentOptionsBase<any, any, any, any, any, any, any, any, any, {}>> | null;
    $emit: (event: string, ...args: any[]) => void;
    $el: any;
    $options: import("vue").ComponentOptionsBase<Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
        msg: string;
    }>>>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, string, {}> & {
        beforeCreate?: ((() => void) | (() => void)[]) | undefined;
        created?: ((() => void) | (() => void)[]) | undefined;
        beforeMount?: ((() => void) | (() => void)[]) | undefined;
        mounted?: ((() => void) | (() => void)[]) | undefined;
        beforeUpdate?: ((() => void) | (() => void)[]) | undefined;
        updated?: ((() => void) | (() => void)[]) | undefined;
        activated?: ((() => void) | (() => void)[]) | undefined;
        deactivated?: ((() => void) | (() => void)[]) | undefined;
        beforeDestroy?: ((() => void) | (() => void)[]) | undefined;
        beforeUnmount?: ((() => void) | (() => void)[]) | undefined;
        destroyed?: ((() => void) | (() => void)[]) | undefined;
        unmounted?: ((() => void) | (() => void)[]) | undefined;
        renderTracked?: (((e: import("vue").DebuggerEvent) => void) | ((e: import("vue").DebuggerEvent) => void)[]) | undefined;
        renderTriggered?: (((e: import("vue").DebuggerEvent) => void) | ((e: import("vue").DebuggerEvent) => void)[]) | undefined;
        errorCaptured?: (((err: unknown, instance: import("vue").ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, import("vue").ComponentOptionsBase<any, any, any, any, any, any, any, any, any, {}>> | null, info: string) => boolean | void) | ((err: unknown, instance: import("vue").ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, import("vue").ComponentOptionsBase<any, any, any, any, any, any, any, any, any, {}>> | null, info: string) => boolean | void)[]) | undefined;
    };
    $forceUpdate: () => void;
    $nextTick: typeof import("vue").nextTick;
    $watch(source: string | Function, cb: Function, options?: import("vue").WatchOptions<boolean> | undefined): import("vue").WatchStopHandle;
} & Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
    msg: string;
}>>> & import("vue").ShallowUnwrapRef<{}> & {} & import("vue").ComponentCustomProperties & {
    $slots: typeof import('./HelloWorld.vue.__VLS_template').default;
};
export default _default;
declare type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
declare type __VLS_TypePropsToRuntimeProps<T> = {
    [K in keyof T]-?: {} extends Pick<T, K> ? {
        type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
    } : {
        type: import('vue').PropType<T[K]>;
        required: true;
    };
};

Problem

Problem is this line: $slots: typeof import('./HelloWorld.vue.__VLS_template').default; that is generated by v0.36. I'm not sure why this is happening but I think one of these two commits causes the issue:

Workaround

Don't use <script setup>.

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  props: {
    msg: {
      type: String,
      required: true,
    },
  },

  setup() {
    return {
      cout: ref(0),
    }
  },
})
</script>

Output

declare const _default: import("vue").DefineComponent<{
    msg: {
        type: StringConstructor;
        required: true;
    };
}, {
    cout: import("vue").Ref<number>;
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
    msg: {
        type: StringConstructor;
        required: true;
    };
}>>, {}>;
export default _default;
@johnsoncodehk
Copy link
Member

Hi @bounoable, this behavior have been change after v0.37.0, please let me know if it works for you or not.

@bounoable
Copy link
Author

Hey @johnsoncodehk, unfortunately the issue still persists but I've found out that the issue is caused by vue-code-gen because of this change: a629054#diff-0ad1ae7339a0d8bf162442af7e41a01d15722af208a4bf756126743c9a232ab6R515

(Given an App.vue), the highlighted line generates this code in App.vue.d.ts when using <script setup>

import("vue").ComponentCustomProps & (new () => {
    $slots: typeof import('./App.vue.__VLS_template').default;
});

I guess __VLS_template is a placeholder that should be replaced like the other __VLS_* placeholders but I couldn't exactly figure out the internals to patch this by myself.

Hope this helps!

@johnsoncodehk johnsoncodehk added the bug Something isn't working label Jun 16, 2022
@johnsoncodehk
Copy link
Member

The latest version of the code is a bit different: https://github.com/johnsoncodehk/volar/blob/3485f7bdcb38b903990a9a8a7b3c3a8428050406/packages/vue-code-gen/src/generators/script.ts#L528

I see the problem now, App.vue.__VLS_template will not emit on vue-tsc, so there should not have $slots define for typed template slots. Thank you. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants