# 2026'da TypeScript ile Vue 3: Tip Güvenli Props, Emits ve Composables
> Vue 3 bileşenlerini TypeScript ile tip güvenli hâle getirmenin pratik rehberi: generic defineProps, tuple defineEmits, tiplenmiş composables, defineModel ve InjectionKey ile mülakat soruları.
- Published: 2026-07-07
- Updated: 2026-07-07
- Author: SharpSkill
- Tags: Vue 3, TypeScript, defineProps, Composables, Frontend
- Reading time: 8 min
---
2026'da TypeScript ile birlikte kullanılan Vue 3, props, olaylar ve yeniden kullanılabilir mantık genelinde tam statik tip denetimi sağlar. `
{{ props.name }}
{{ props.role }}
```
`role` prop'u artık iki string literaliyle sınırlandırılmıştır; bu nedenle `role="guest"` geçmek derlemede hata verir. TypeScript ile `defineProps`'a başvurmanın temel nedeni budur: [resmi Vue TypeScript rehberi](https://vuejs.org/guide/typescript/composition-api.html) generic biçimi `
```
Vue 3.5, bugün daha kısa olan **reaktif prop destructuring**'i kararlı hâle getirdi. `defineProps` sonucunu destructure edip aynı ifadede bir varsayılan atamak tamamen reaktif kalır — derleyici, arka planda her erişimi yeniden `props.x`'e yazar.
```vue
{{ label }}
```
> **Destructure edilmiş props'ta reaktiflik tuzağı**
>
> Destructure edilmiş props, şablonda ve `computed` içinde reaktif kalır; ancak destructure edilmiş bir değeri doğrudan `watch`'a veya bir composable'a geçirmek onu yalnızca bir kez okur ve reaktif bağı koparır. Bir ref gerektiğinde bu değeri bir getter içine sarın — `watch(() => color, ...)` — veya `toRef(props, 'color')` ile dönüştürün.
Bu, yaygın bir mülakat tuzağıdır: adaylar destructure edilmiş değişkenin düz bir değer olduğunu varsayar; oysa derleyici aslında her okumayı yeniden `props.color`'a yönlendirmiştir.
## defineEmits ile tip güvenli emits
Olaylar, props ile aynı titizliği hak eder. Generic `defineEmits`, her olay adını ve yükünü bir tuple olarak tanımlayarak üst bileşene otomatik tamamlama, alt bileşene ise doğru argümanların yayıldığına dair derleme zamanı denetimi sağlar.
```vue
```
Bu tuple biçimi, eski çağrı imzası sözdizimini (`(e: 'search', q: string): void`) yerini aldı; çünkü daha okunaklıdır ve aşırı yükleme olmadan birden çok olayı destekler. Bir olay veri taşımıyorsa, boş bir tuple `[]` bunu açıkça belgeler. Tiplenmiş emits'i tiplenmiş props ile eşleştirmek, tüm genel arayüzü çalışma zamanından önce doğrulanabilir bileşenler üretir — [Vue Composition API rehberinde](/blog/vue-nuxt/vue-3-composition-api-complete-guide) ele alınan aynı disiplin.
## Yeniden kullanılabilir mantık için composables tipleme
Composables düz fonksiyonlardır, bu yüzden sıradan TypeScript kurallarına uyarlar — ancak birkaç kural onları ergonomik tutar. Çıkarım açık olmadığında `Ref` tiplerini açıkça döndürün ve bir composable, bir API yanıtı gibi rastgele veriyi sardığında generic kullanın.
```ts
// useFetch.ts
import { ref, type Ref } from 'vue'
interface UseFetchReturn {
data: Ref
error: Ref
loading: Ref
}
// Generic flows through to the caller's typed data
export function useFetch(url: string): UseFetchReturn {
const data = ref(null) as Ref
const error = ref(null)
const loading = ref(true)
fetch(url)
.then((r) => r.json())
.then((json: T) => { data.value = json })
.catch((e: Error) => { error.value = e })
.finally(() => { loading.value = false })
return { data, error, loading }
}
```
Çağrı noktasında generic parametre, `data`'yı hiçbir ek açıklama olmadan tamamen tiplenmiş hâle getirir:
```ts
// UserList.vue (script setup)
interface User { id: number; name: string }
// data is Ref — inferred from the generic
const { data: users, loading } = useFetch('/api/users')
```
Döndürülen nesneyi açıkça tipleme (`UseFetchReturn`) o birkaç fazladan satıra değer: sözleşmeyi belgeler, iç ref'lerin kazara sızmasını önler ve tüketicilere içe aktarılacak tek bir tip sunar. Argüman aşırı yüklemeleri ve yaşam döngüsüne duyarlı temizlik gibi daha derin composable desenleri için [gelişmiş Vue composables rehberine](/blog/vue-nuxt/advanced-vue-3-composables-reusable-patterns) bakın.
## İki yönlü bağlama için defineModel tipleme
Vue 3.4'ten beri kararlı olan `defineModel`, eski `modelValue` prop'unu ve `update:modelValue` emit'ini tek bir yazılabilir ref'e daraltır. Generic parametresi bağlamanın her iki yönünü aynı anda tipler.
```vue
```
Adlandırılmış modeller — `defineModel('title')` — `v-model:title` ile eşlenir ve aynı tiplemeyi alır. Bu, manuel prop-ve-emit deseninin gizlediği tüm bir uyumsuz yük hataları sınıfını ortadan kaldırır.
## Şablon ref'lerini ve bileşen örneklerini tipleme
Bir DOM düğümüne veya alt bileşene `ref` üzerinden erişmek, tiplenmemiş Vue kodunun en sık `any`'ye düştüğü yerdir. Çözüm, `useTemplateRef`'i (Vue 3.5+) veya `ref`'in kendisini eleman tipiyle parametreleştirmektir; böylece özellik erişimi gerçek DOM arayüzüne karşı denetlenir.
```vue
```
Bir alt bileşene yapılan referans için `InstanceType`, bileşenin genel tipini çıkararak alt bileşenin `defineExpose` aracılığıyla bildirdiği her şeyi açığa çıkarır. Bu, üstten alta metot çağrılarının tahmin edilmek yerine tamamen denetlenmesini sağlar.
```vue
```
## InjectionKey ile tip güvenli provide ve inject
Bileşen ağacı boyunca bağımlılık enjeksiyonu, anahtar tip bilgisini taşımadıkça bu bilgiyi yitirir. `InjectionKey`, bir değerin tipini anahtarına bağlayan tiplenmiş bir semboldür; böylece `provide` ve `inject` manuel dönüşüm olmadan senkron kalır.
```ts
// theme-key.ts
import type { InjectionKey, Ref } from 'vue'
export interface ThemeContext {
mode: Ref<'light' | 'dark'>
toggle: () => void
}
// The key permanently associates the ThemeContext type with this symbol
export const ThemeKey: InjectionKey = Symbol('theme')
```
```ts
// provider (script setup) — value must match ThemeContext or it fails to compile
provide(ThemeKey, { mode, toggle })
// consumer — theme is inferred as ThemeContext | undefined
const theme = inject(ThemeKey)
theme?.toggle()
```
Şekli `ThemeContext` ile eşleşmeyen bir değer sağlamak, enjeksiyon noktasında bir derleme hatasıdır; bu da uzak bileşenler arasındaki tutarsızlığı üretime ulaşmadan yakalar.
## Sık sorulan Vue TypeScript mülakat soruları
Mülakatçılar, adayın derleme zamanı tipleri ile çalışma zamanı davranışı arasındaki sınırı anlayıp anlamadığını yoklar. Sıkça tekrarlanan birkaç soru ve keskin yanıtları:
- **Çalışma zamanı nesne biçimi yerine neden `defineProps()` tercih edilir?** Generic props, çalışma zamanı bildirimlerinin ifade edemediği union tiplerini, fonksiyon imzalarını ve iç içe şekilleri ifade eder ve tekrarlanan tip/çalışma zamanı tanımlarını ortadan kaldırır.
- **Destructure edilmiş props reaktif midir?** Vue 3.5+ ile evet, çünkü derleyici erişimi `props.x`'e yeniden yazar. Ancak `watch`'a veya bir composable'a geçirilen destructure edilmiş *değerler* bir kez okunur — bir getter veya `toRef` kullanın.
- **Yükü olmayan bir olay nasıl tiplenir?** Boş bir tuple ile: `defineEmits<{ close: [] }>()`.
- **`defineModel` neyin yerini alır?** `modelValue` prop'u ve `update:modelValue` emit çiftini; tek bir tiplenmiş yazılabilir ref hâlinde birleştirir.
Bu konuları gerçek bir soru bankasına karşı çalışmak, mülakatların ödüllendirdiği refleksleri keskinleştirir — [Vue composables mülakat modülü](/technologies/vue-nuxt/interview-questions/vue-composables) tam olarak bu desenleri çalıştırır. Araçlar da önemlidir: tip hatalarının birleştirmeyi engellemesi için CI'da `vue-tsc` çalıştırın ve composable generic'leri işin içine girdiğinde [TypeScript el kitabına](https://www.typescriptlang.org/docs/handbook/2/generics.html) başvurun. Editör deneyimi, bu makroları okuyup hataları yerinde gösteren [Vue'nun resmi Volar aracıyla](https://github.com/vuejs/language-tools) sağlanır.
## Sonuç
- Çalışma zamanı bildirimlerinin yakalayamadığı union tiplerini, isteğe bağlı alanları ve callback prop'larını ifade etmek için generic `defineProps()` kullanın.
- Vue 3.5+ ile satır içi varsayılanlar taşıyan reaktif prop destructuring'i tercih edin ve ortak bir varsayılanlar nesnesi daha anlaşılır olduğunda yalnızca `withDefaults`'a başvurun.
- Yüklerin hem alt hem üst bileşende derleme zamanında denetlenmesi için olayları `defineEmits`'in tuple biçimiyle tipleyin.
- Composable dönüş tiplerini açıkça açıklayın ve çağıranın sağladığı veri tiplerini baştan sona iletmek için generic kullanın.
- İki yönlü bağlama için `defineModel()` benimseyin; böylece prop-artı-emit tekrarını tek bir tiplenmiş ref'e daraltırsınız.
- Tip gerilemelerinin üretime ulaşmak yerine build'i durdurması için sürekli entegrasyonda `vue-tsc` çalıştırın.
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/tr/blog/vue-nuxt/vue-3-typescript-type-safe-props-emits-composables