Kompozisyon API ile TypeScript
Kompozisyon API ile TypeScript
Bu sayfanın
TypeScript ile Vue Kullanımı
üzerine genel bir bakış okuduğunuzu varsayıyor.
Bileşen Props'larının Türü
`` Kullanımı
`kullanırken,
defineProps()` makrosu, argümanına dayalı olarak props türlerini çıkarmayı destekler:
<script setup lang="ts">
const props = defineProps({
foo: { type: String, required: true },
bar: Number
})
props.foo // string
props.bar // number | undefined
</script>
Bu, "çalışma zamanı beyanı" olarak adlandırılır, çünkü defineProps()
'a geçirilen argüman, çalışma zamanı props
seçeneği olarak kullanılacaktır.
Ancak, genellikle saf türler ile props tanımlamak için, generic tür argümanı kullanmak daha basittir:
<script setup lang="ts">
const props = defineProps<{
foo: string
bar?: number
}>()
</script>
Bu, "türe dayalı beyan" olarak adlandırılır. Derleyici, tür argümanına dayalı olarak eşdeğer çalışma zamanı seçeneklerini çıkarmaya çalışacaktır. Bu durumda, ikinci örneğimiz birinci örnekle tamamen aynı çalışma zamanı seçeneklerine derlenir.
Türe dayalı beyan veya çalışma zamanı beyanını kullanabilirsiniz, ancak her ikisini aynı anda kullanamazsınız.
Ayrıca props türlerini ayrı bir arayüze taşıyabiliriz:
<script setup lang="ts">
interface Props {
foo: string
bar?: number
}
const props = defineProps<Props>()
</script>
Bu, Props
bir dış kaynaktan aktarılmış olsa bile çalışır. Bu özellik, TypeScript'in Vue'nun bir eş bağımlılığı olmasını gerektirir.
<script setup lang="ts">
import type { Props } from './foo'
const props = defineProps<Props>()
</script>
Söz dizimi Sınırlamaları
3.2 ve altı sürümlerde, defineProps()
için generic tür parametresi bir tür literal'ı veya yerel bir arayüze referans ile sınırlıdır.
Bu sınırlama 3.3'te kaldırılmıştır. Vue'nun en son sürümü, tür parametre pozisyonunda aktarılmış ve sınırlı bir karmaşık tür kümesine referans vermeyi destekler. Ancak, türden çalışma zamanı dönüşümünün hala AST tabanlı olması nedeniyle, gerçek tür analizine ihtiyaç duyan bazı karmaşık türler, örneğin koşullu türler desteklenmez. Bir prop'un türü için koşullu türler kullanabilirsiniz, ancak tüm props nesnesi için kullanamazsınız.
Props Varsayılan Değerleri
Türe dayalı beyan kullanırken, props için varsayılan değerler beyan etme yeteneğimizi kaybederiz. Bu, Reaktif Props Yapılandırması
ile çözülebilir :
interface Props {
msg?: string
labels?: string[]
}
const { msg = 'hello', labels = ['one', 'two'] } = defineProps<Props>()
3.4 ve altı sürümlerde, Reaktif Props Yapılandırması varsayılan olarak etkin değildir. Alternatif olarak, withDefaults
derleyici makrosunu kullanabilirsiniz:
interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
Bu, eşdeğer çalışma zamanı props varsayılan
seçeneklerine derlenecektir. Ayrıca, withDefaults
yardımcı programı varsayılan değerler için tür kontrolü sağlar ve döndürülen props
türünün, varsayılan değerlerin beyan edildiği özellikler için isteğe bağlı bayrakların kaldırıldığından emin olur.
Değişken referans türleri (diziler veya nesneler gibi) için varsayılan değerlerin withDefaults
kullanırken işlevlere sarılması gerektiğini lütfen unutmayın, bu yanlışlıkla değişimi ve dış etkileri önler. Bu, her bileşen örneğinin varsayılan değerinin kendi kopyasını almasını sağlar. Bu, yapılandırma ile varsayılan değerler kullanırken gerekli değildir.
`` Olmadan
`kullanmıyorsanız, props tür çıkarımını etkinleştirmek için
defineComponent()kullanmak gereklidir. Şuraya geçirilen props nesnesinin türü
props` seçeneğinden çıkarılır.
import { defineComponent } from 'vue'
export default defineComponent({
props: {
message: String
},
setup(props) {
props.message // <-- tür: string
}
})
Karmaşık prop türleri
Türe dayalı beyan ile bir prop, herhangi bir diğer türde olduğu gibi karmaşık bir tür kullanabilir:
<script setup lang="ts">
interface Book {
title: string
author: string
year: number
}
const props = defineProps<{
book: Book
}>()
</script>
Çalışma zamanı beyanı için PropType
yardımcı türünü kullanabiliriz:
import type { PropType } from 'vue'
const props = defineProps({
book: Object as PropType<Book>
})
Bu, props
seçeneğini doğrudan tanımlarken de aynı şekilde çalışır:
import { defineComponent } from 'vue'
import type { PropType } from 'vue'
export default defineComponent({
props: {
book: Object as PropType<Book>
}
})
props
seçeneği, Genellikle Opsiyonel API ile daha yaygın olarak kullanılır, bu nedenle Opsiyonel API ile TypeScript
rehberinde daha detaylı örnekler bulacaksınız. Bu örneklerde gösterilen teknikler, defineProps()
ile yapılan çalışma zamanı beyanlarına da uygulanabilir.
Bileşen Emit'lerinin Türü
`içerisinde,
emit` fonksiyonu hem çalışma zamanı beyanı hem de tür beyanı kullanılarak türlendirilebilir:
<script setup lang="ts">
// çalışma zamanı
const emit = defineEmits(['change', 'update'])
// opsiyonel tabanlı
const emit = defineEmits({
change: (id: number) => {
// doğrulama geçişi / başarısızlığı belirtmek için
// `true` veya `false` döndürüyor
},
update: (value: string) => {
// doğrulama geçişi / başarısızlığı belirtmek için
// `true` veya `false` döndürüyor
}
})
// tür tabanlı
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
// 3.3+: alternatif, daha özlü sözdizimi
const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()
</script>
Tür argümanı aşağıdaki gibi olabilir:
- Bir çağrılabilir fonksiyon türü, ancak Çağrı İmzası ile bir tür literal'ı olarak yazılmıştır. Dönülen
emit
fonksiyonunun türü olarak kullanılacaktır. - Anahtarların etkinlik adları olduğu ve değerlerin etkinlik için ek kabul edilen parametreleri temsil eden dizi / demet türleri olduğu bir tür literal'ı. Yukarıdaki örnek, her argümanın açık bir adı olması için adlandırılmış demetler kullanmaktadır.
Gördüğümüz gibi, tür beyanı, yayılan etkinliklerin tür kısıtları üzerinde daha ince ayrıntılı kontrol sağlar.
`kullanmıyorsanız,
defineComponent()kurulum bağlamında yayınlanan
emit` fonksiyonu için izin verilen etkinlikleri çıkarım yapabilir:
import { defineComponent } from 'vue'
export default defineComponent({
emits: ['change'],
setup(props, { emit }) {
emit('change') // <-- tür kontrolü / otomatik tamamlama
}
})
ref()
Türlendirme
Refs, başlangıç değerinden tür çıkarımı yapar:
import { ref } from 'vue'
// çıkarılan tür: Ref<number>
const year = ref(2020)
// => TS Hatası: Tür 'string' tür 'number'a atanamaz.
year.value = '2020'
Bazen bir ref'in iç değerine karmaşık türler belirtmemiz gerekebilir. Bunu Ref
türünü kullanarak yapabiliriz:
import { ref } from 'vue'
import type { Ref } from 'vue'
const year: Ref<string | number> = ref('2020')
year.value = 2020 // tamam!
Veya ref()
çağrıldığında varsayılan çıkarımı geçersiz kılmak için generic bir argüman geçirerek:
// sonuç türü: Ref<string | number>
const year = ref<string | number>('2020')
year.value = 2020 // tamam!
Eğer bir generic tür argümanı belirlerseniz ancak başlangıç değerini atlamazsanız, sonuç türü undefined
içeren bir birleşim türü olur:
// çıkarılan tür: Ref<number | undefined>
const n = ref<number>()
reactive()
Türlendirme
reactive()
da argümanından tür çıkarımı yapar:
import { reactive } from 'vue'
// çıkarılan tür: { title: string }
const book = reactive({ title: 'Vue 3 Rehberi' })
Bir reactive
özelliğini açıkça türlendirmek için arayüzleri kullanabiliriz:
import { reactive } from 'vue'
interface Book {
title: string
year?: number
}
const book: Book = reactive({ title: 'Vue 3 Rehberi' })
reactive()
'nin generic argümanını kullanmanız önerilmez çünkü dönen tür, iç içe ref açma işlemini yöneten, generic argüman türünden farklıdır.
computed()
Türlendirme
computed()
işleminin döndürdüğü değere bağlı olarak tür çıkarımı yapar:
const count = ref(0)
// çıkarılan tür: ComputedRef<number>
const double = computed(() => count.value * 2)
// => TS Hatası: `split` özelliği 'number' türünde yok
const result = double.value.split('')
Açıkça bir tür belirtmek için generic bir argüman da verebilirsiniz:
const double = computed<number>(() => {
// Bu bir sayı döndürmezse tür hatası
})
Olay İşleyicilerinin Türlendirilmesi
Yerel DOM olaylarıyla uğraşırken, işleyiciye geçirdiğimiz argümanı doğru bir şekilde türlendirmek yararlı olabilir. Şu örneğe bir bakalım:
<script setup lang="ts">
function handleChange(event) {
// `event` dolaylı olarak `any` türüne sahiptir
console.log(event.target.value)
}
</script>
<template>
<input type="text" @change="handleChange" />
</template>
Tür notasyonu olmadan, event
argümanı dolaylı olarak any
türüne sahip olacaktır. Bu, "strict": true
veya "noImplicitAny": true
kullanıldığında bir TS hatasına yol açar. Bu nedenle, olay işleyicilerinin argümanlarını açıkça yazmanız önerilir. Ayrıca, event
'in özelliklerine erişirken tür varsayımları yapmanız gerekebilir:
function handleChange(event: Event) {
console.log((event.target as HTMLInputElement).value)
}
Provide / Inject Türlendirme
Provide ve inject genellikle ayrı bileşenlerde gerçekleştirilir. Enjekte edilen değerlerin doğru bir şekilde türlendirilmesi için, Vue InjectionKey
arayüzünü sağlar; bu, Symbol
uzantılı bir generic türdür. Sağlayıcı ve tüketici arasındaki enjekte edilen değerin türünü senkronize etmek için kullanılabilir:
import { provide, inject } from 'vue'
import type { InjectionKey } from 'vue'
const key = Symbol() as InjectionKey<string>
provide(key, 'foo') // string olmayan bir değer sağlamak hata verecektir
const foo = inject(key) // foo'nun türü: string | undefined
Enjeksiyon anahtarını ayrı bir dosyada tutması önerilir, böylece birden fazla bileşende ithal edilebilir.
Dize enjeksiyon anahtarları kullanırken, enjekte edilen değerin türü unknown
olacaktır ve açıkça bir generic tür argümanı ile belirtilmesi gerekir:
const foo = inject<string>('foo') // tür: string | undefined
Enjekte edilen değerin hala undefined
olabileceğini unutmayın, çünkü bir sağlayıcının bu değeri çalışma zamanında sağlaması garantisi yoktur.
undefined
türü, varsayılan bir değer sağlayarak kaldırılabilir:
const foo = inject<string>('foo', 'bar') // tür: string
Değerin her zaman sağlandığından emin iseniz, değeri zorla biçimlendirebilirsiniz:
const foo = inject('foo') as string
Şablon Refs Türlendirmesi
Vue 3.5 ve @vue/language-tools
2.1 ile (hem IDE dil hizmetine hem de vue-tsc
'ye güç veren), SFC'lerde useTemplateRef()
ile oluşturulan refs'lerin türü, eşleşen ref
niteliğinin kullanıldığı elemanın üzerine otomatik olarak çıkarılabilir.
Otomatik çıkarımın mümkün olmadığı durumlarda, şablon referansını açık bir türle biçimlendirmek için generic argümanı kullanabilirsiniz:
const el = useTemplateRef<HTMLInputElement>('el')
3.5'ten Önceki Kullanım
Şablon refs, açık bir generic tür argümanı ve başlangıç değeri olarak null
ile oluşturulmalıdır:
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const el = ref<HTMLInputElement | null>(null)
onMounted(() => {
el.value?.focus()
})
</script>
<template>
<input ref="el" />
</template>
Doğru DOM arayüzünü elde etmek için MDN gibi sayfalara göz atabilirsiniz.
Sıkı tür güvenliği için, el.value
'ya erişirken opsiyonel zincirleme veya tür koruyucuları kullanmanız gereklidir. Çünkü başlangıç ref değeri null
dur ve bileşen monte edilene kadar null
olarak ayarlanabilir, ayrıca v-if
ile ilgili eleman kaldırıldığında null
olarak ayarlanabilir.
Bileşen Şablon Refs Türlendirmesi
Vue 3.5 ve @vue/language-tools
2.1 ile (hem IDE dil hizmetine hem de vue-tsc
'ye güç veren), SFC'lerde useTemplateRef()
ile oluşturulan refs'lerin türü, eşleşen ref
niteliğinin kullanıldığı eleman veya bileşenin üzerinde otomatik olarak çıkarılabilir.
Otomatik çıkarımın mümkün olmadığı durumlarda (örneğin, SFC dışı kullanım veya dinamik bileşenler), şablon referansını açık bir türle biçimlendirmek için generic argümanı kullanabilirsiniz.
İthal edilen bir bileşenin örnek türünü almak için önce türünü typeof
ile almalıyız, ardından TypeScript'in yerleşik InstanceType
yardımcı türünü kullanarak örnek türünü çıkarmalıyız:
<!-- App.vue -->
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import Foo from './Foo.vue'
import Bar from './Bar.vue'
type FooType = InstanceType<typeof Foo>
type BarType = InstanceType<typeof Bar>
const compRef = useTemplateRef<FooType | BarType>('comp')
</script>
<template>
<component :is="Math.random() > 0.5 ? Foo : Bar" ref="comp" />
</template>
Tam bileşenin türü mevcut değilse veya önemli değilse, ComponentPublicInstance
kullanılabilir. Bu sadece tüm bileşenler tarafından paylaşılan $el
gibi özellikleri içerir:
import { useTemplateRef } from 'vue'
import type { ComponentPublicInstance } from 'vue'
const child = useTemplateRef<ComponentPublicInstance>('child')
Eğer referans verilen bileşen bir generic bileşen
ise, örneğin MyGenericModal
:
<!-- MyGenericModal.vue -->
<script setup lang="ts" generic="ContentType extends string | number">
import { ref } from 'vue'
const content = ref<ContentType | null>(null)
const open = (newContent: ContentType) => (content.value = newContent)
defineExpose({
open
})
</script>
Parametre olarak ComponentExposed
'i vue-component-type-helpers
kütüphanesinden kullanarak referans vermeniz gerekecek; çünkü InstanceType
çalışmaz.
<!-- App.vue -->
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import MyGenericModal from './MyGenericModal.vue'
import type { ComponentExposed } from 'vue-component-type-helpers'
const modal = useTemplateRef<ComponentExposed<typeof MyGenericModal>>('modal')
const openModal = () => {
modal.value?.open('newValue')
}
</script>
@vue/language-tools
2.1+ ile, statik şablon refs'lerinin türleri otomatik olarak çıkarılabilir ve yukarıdaki gereksizlik yalnızca uç durumlarda gereklidir.