unplugin-dts icon indicating copy to clipboard operation
unplugin-dts copied to clipboard

PropType is ignored in Vue files with `<script setup>`

Open kadiryazici opened this issue 3 years ago • 2 comments

Hi, when we create our component as SFC and use script setup Vite Plugin DTS just ignores type and uses ArrayConstructor ObjectConstructor like types, not the ones we specified.

But in normal vue file without script setup it correct d.ts file but not 100% accurate.

You can see built types in dist/types folder created from src folder. https://github.com/kadiryazici/vite-plugin-dts-issue

Script Setup One

Component code:

<script lang="ts">
export interface Props {
  items: { text: string }[];
}

export default {
  name: 'TheListeleme',
};
</script>

<script lang="ts" setup>
withDefaults(defineProps<Props>(), {
  items: () => [],
});
</script>

<template>
  <ul>
    <li
      v-for="item in items"
      :key="item.text"
    >
      {{ item.text }}
    </li>
  </ul>
  {{ 5 }}
</template>

Generated d.ts code, look at line 7 it says ArrayConstructor

export interface Props {
    items: {
        text: string;
    }[];
}
declare const _sfc_main: import("vue").DefineComponent<{
    items: {
        type: ArrayConstructor;
        required: true;
        default: () => any[];
    };
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
    items: {
        type: ArrayConstructor;
        required: true;
        default: () => any[];
    };
}>>, {
    items: unknown[];
}>;
export default _sfc_main;

With normal setup

Component code:

<script lang="ts">
import { defineComponent, type PropType } from 'vue';

type Item = { text: string };

export interface Props {
  items: Item[];
}

export default defineComponent({
  name: 'TheListeleme',
  props: {
    items: {
      type: Array as PropType<Props['items']>,
      default: () => [],
    },
  },
});
</script>

<template>
  <ul>
    <li
      v-for="item in items"
      :key="item.text"
    >
      {{ item.text }}
    </li>
  </ul>
  {{ 5 }}
</template>

DTS code:

  • This time types are accurate but approach is different, instead of Props['items'] it just uses Item[], not the same as source code.
import { type PropType } from 'vue';
declare type Item = {
    text: string;
};
export interface Props {
    items: Item[];
}
declare const _sfc_main: import("vue").DefineComponent<{
    items: {
        type: PropType<Item[]>;
        default: () => any[];
    };
}, unknown, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
    items: {
        type: PropType<Item[]>;
        default: () => any[];
    };
}>>, {
    items: Item[];
}>;
export default _sfc_main;

With TS file

Component code:

import { h, defineComponent, type PropType, renderList } from 'vue';

interface Props {
  items: { text: string }[];
}

export default defineComponent({
  name: 'TheListeleme',
  props: {
    items: {
      type: Array as PropType<Props['items']>,
      default: () => [],
    },
  },
  setup(props) {
    return () =>
      h(
        'ul',
        null,
        renderList(props.items, (item) => h('li', {}, item.text)),
      );
  },
});

DTS Code:

  • It gets rid of Props here again
import { type PropType } from 'vue';
export interface Props {
    items: {
        text: string;
    }[];
}
declare const _default: import("vue").DefineComponent<{
    items: {
        type: PropType<{
            text: string;
        }[]>;
        default: () => any[];
    };
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
    items: {
        type: PropType<{
            text: string;
        }[]>;
        default: () => any[];
    };
}>>, {
    items: {
        text: string;
    }[];
}>;
export default _default;

kadiryazici avatar Sep 08 '22 00:09 kadiryazici

It needs to use the js way to define props, and the ts way will not be able to infer types after the compiler compiled.

qmhc avatar Sep 11 '22 13:09 qmhc

vue-tsc is able create correct, maybe that behavior can be injectable?

kadiryazici avatar Sep 12 '22 08:09 kadiryazici

I tried building the first example with up-to-date vite-plugin-dts, Vue & Vite and got:

import type { PropType as __PropType } from 'vue';
export interface Props {
    items: {
        text: string;
    }[];
}
declare const _sfc_main: import("vue").DefineComponent<{
    items: {
        type: __PropType<{
            text: string;
        }[]>;
        required: true;
        default: () => never[];
    };
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
    items: {
        type: __PropType<{
            text: string;
        }[]>;
        required: true;
        default: () => never[];
    };
}>>, {
    items: {
        text: string;
    }[];
}>;
export default _sfc_main;

Perhaps something has changed somewhere else that fixes this?

segevfiner avatar May 11 '23 00:05 segevfiner

Fxied.

qmhc avatar Jun 30 '23 03:06 qmhc