typescript - Vue3 bileşenler arasında paylaşılan props


Son zamanlarda Vue2’den Vue3’e geçtim ama birden fazla bileşen arasında paylaşılan props kullanmanın en iyi uygulamasının ne olduğu konusunda biraz kafam karışık. "type", "name" gibi ortak props paylaşan input bileşenleri yapmak istiyorum. Daha önce bunu mixins ile yapıyordum ama bunun hala en iyi yol olup olmadığını merak ediyorum.

Size options-api aracılığıyla denediğim bir örnek vereyim:

// Home.vue
<template>
    <p>Home</p>
    <p>{{ type }}</p>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { sharedInputProps } from '../admin/composables/sharedInputProps'

export default defineComponent({
    props: {
        ...sharedInputProps,
    },
    setup() {
        return {
        }
    },
})
</script>
// sharedInputProps.ts
import { ComponentPropsOptions } from 'vue'

export const sharedInputProps: ComponentPropsOptions = {
    type: {
        type: String,
        required: true,
        default: 'text',
    }
}

Bu işe yarıyor ama IDE'mde Home.vue'deki props'ların ne olduğu konusunda herhangi bir tip ipucu/otomatik tamamlama almıyorum (bu durumda <p>{{ type }}</p>.

Bunu mixinlerle şöyle yapardım:

// Home.vue
<template>
    <p>Home</p>
    <p>{{ type }}</p>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import InputProps from '../admin/mixins/InputProps.vue'


export default defineComponent({
    mixins:[
        InputProps,
    ],
    setup() {
        return {
        }
    },
})
</script>
// InputProps.vue
<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
    props: {
        type: {
            type: String,
            required: true,
            default: 'text',
        }
    },
})
</script>

Bu amaçlandığı gibi çalışıyor ve bana doğru tür ipuçları/otomatik tamamlama sağlıyor.

Ama merak ediyorum, bu composition-api ile defineProps yöntemi kullanılarak nasıl yapılmalı. Aşağıda gösterildiği gibi, tip ipucu/otomatik tamamlama ile Home.vue içinde propsları doğrudan tanımlayarak çalıştırmayı başardım:

// Home.vue
<template>
    <p>Home</p>
    <p>{{ type }}</p>
</template>

<script setup lang="ts">
import { defineProps, withDefaults } from 'vue'
interface Props {
    type?: string
}

const props = withDefaults(defineProps<Props>(), {
    type: 'text',
})

</script>

Ama belgelerde (https://vuejs.org/guide/typescript/composition-api.html#typing-component-props) belirtildiği gibi, dış bir dosyadan yüklenemez.

Yani sorum şu: composition-api ile harici bir dosya kullanmak desteklenmediği için (henüz mı?) ve options-api ile harici bir dosya kullanıp bir nesneyi yapı bozucu (spread) operatörü ile açmak tür ipuçları/otomatik tamamlama vermiyorsa, mixins hâlâ props paylaşmak için en iyi uygulama mı? Yoksa sharedProps.ts dosyamda (ya da başka bir yerde) bir şeyi yanlış mı yapılandırıyorum?

En son Vue 3 sürümünü (3.2.47) çalıştırıyorum ve IDE olarak en son PHPStorm sürümünü (2023.1) kullanıyorum.

Cevap #1

ComponentPropsOptions türü, sharedInputProps'in varsayılan olarak türlendirilmesini engeller.

Eğer sharedInputProps öğeleri ComponentPropsOptions türü ile uyumlu olması gerekiyorsa, TypeScript 4.9 veya daha yüksek sürümlerde satisfies kullanılabilir:

export const sharedInputProps = {
    type: {
        type: String,
        required: true,
        default: 'text',
    }
} satisfies ComponentPropsOptions

Bu, props: { ...sharedInputProps } olarak kullanıldığında doğru tipi korur ve yanlışsa tanımlandığı yerde hatayı fark etmeyi sağlar.