JavaScript'te bir bileşene yanlış prop geçtiğinizde hatayı çalışma zamanında öğrenirsiniz — muhtemelen production'da. TypeScript ile bu hata derleme anında, kodunuzu yazdığınız anda yakalanır.
Props Tanımlamak: interface mi type mı?
İkisi de çalışır, ancak bileşen props'ları için interface tercih edilir — daha okunabilir hata mesajları üretir ve declaration merging destekler.
// ✅ Tercih edilen
interface ButtonProps {
label: string
variant?: 'primary' | 'outline' | 'ghost'
size?: 'sm' | 'md' | 'lg'
disabled?: boolean
onClick?: () => void
}
export function Button({ label, variant = 'primary', size = 'md', ...rest }: ButtonProps) {
return <button className={cn(base, variants[variant], sizes[size])} {...rest}>{label}</button>
}children'ı Doğru Tipler
React.PropsWithChildren kullanmak yerine children'ı açıkça tanımlamak daha esnektir — ne tür children'a izin verdiğinizi net gösterir.
import { ReactNode } from 'react'
interface CardProps {
title: string
children: ReactNode // herhangi bir render edilebilir içerik
footer?: ReactNode // opsiyonel slot
className?: string
}
// Sadece string kabul eden bileşen için:
interface LabelProps {
children: string
}Generic Bileşenler
Bir liste bileşeni düşünün: her veri tipiyle çalışması gerekiyor ama tip güvenliğini kaybetmek istemiyorsunuz. Generics tam bu durumda devreye girer.
interface ListProps<T> {
items: T[]
renderItem: (item: T, index: number) => ReactNode
keyExtractor: (item: T) => string
emptyText?: string
}
export function List<T>({ items, renderItem, keyExtractor, emptyText = 'Sonuç yok' }: ListProps<T>) {
if (items.length === 0) return <p>{emptyText}</p>
return (
<ul>
{items.map((item, i) => (
<li key={keyExtractor(item)}>{renderItem(item, i)}</li>
))}
</ul>
)
}
// Kullanım — tip otomatik çıkarılır:
<List
items={users}
keyExtractor={(u) => u.id}
renderItem={(u) => <UserCard user={u} />}
/>💡 İpucu
as const kullanarak sabit değerleri tuple/literal olarak daraltın. Bu sayede "primary" | "outline" gibi union tipler otomatik oluşur, ayrı tanımlamaya gerek kalmaz.
Custom Hook Tipleri
function useLocalStorage<T>(key: string, initial: T) {
const [value, setValue] = useState<T>(() => {
if (typeof window === 'undefined') return initial
try {
const item = localStorage.getItem(key)
return item ? (JSON.parse(item) as T) : initial
} catch {
return initial
}
})
const set = (v: T | ((prev: T) => T)) => {
setValue(v)
localStorage.setItem(key, JSON.stringify(typeof v === 'function' ? (v as (p: T) => T)(value) : v))
}
return [value, set] as const
// ^ tuple döndürür, [T, Dispatch<...>] çıkarımı doğru olur
}Discriminated Union ile Conditional Props
Bir bileşenin farklı modlarda farklı prop seti alması gerektiğinde discriminated union'lar hayat kurtarır.
type AlertProps =
| { variant: 'info'; message: string }
| { variant: 'confirm'; message: string; onConfirm: () => void; onCancel: () => void }
| { variant: 'error'; message: string; error: Error }
// variant='confirm' seçilince TypeScript onConfirm ve onCancel'ı zorunlu kılar.
// variant='info' seçilince bu prop'lar mevcut bile değildir.