# React Native ve TypeScript 2026: Tip Güvenli Mimari ve Mülakat Soruları > React Native'de TypeScript ile tip güvenli mimari oluşturma: Strict API, TurboModule Codegen, React Navigation 7 tiplendirmesi ve discriminated union'lar. - Published: 2026-06-16 - Updated: 2026-06-16 - Author: SharpSkill - Tags: react-native, typescript, mobile-development, new-architecture, turbomodules - Reading time: 9 min --- React Native ekosistemi 2026'da TypeScript-first bir yapıya tamamen geçiş yapmış durumda. New Architecture'ın stabil hale gelmesiyle birlikte, TurboModules ve Fabric renderer artık compile-time tip güvenliği sunuyor. Codegen sayesinde native modüller otomatik olarak TypeScript interface'lerinden türetiliyor ve runtime hatalarının büyük kısmı build aşamasında yakalanıyor. Modern React Native projeleri strict TypeScript konfigürasyonu, tip güvenli navigasyon ve discriminated union pattern'leriyle production-ready mobil uygulamalar geliştiriyor. > **2026'da Değişenler:** React Native 0.76+ sürümleri varsayılan olarak TurboModules ve Fabric renderer ile geliyor. TypeScript, template projelerde artık opsiyonel değil zorunlu bir seçim. `exactOptionalPropertyTypes` ve `noUncheckedIndexedAccess` flag'leri community standartlarının parçası haline geldi. ## TypeScript Neden React Native'de Varsayılan Haline Geldi React Native'in JavaScript kökleri olmasına rağmen, ecosystem 2026 itibarıyla TypeScript'i standard olarak benimsedi. Bunun arkasında birkaç kritik neden var. İlk olarak, New Architecture'ın JSI (JavaScript Interface) üzerinden native tarafla doğrudan konuşması, tip güvenliğini zorunlu kılıyor. Eski Bridge mimarisinde JSON serializasyon hataları runtime'da ortaya çıkarken, TurboModules bu hataları compile-time'da yakalar. İkinci olarak, React Navigation gibi temel kütüphaneler TypeScript-first API'ler sunuyor. Stack navigator'da bir ekrana yanlış parametre göndermek, kod yazarken hata veriyor. Üçüncü olarak, Metro bundler'ın performans iyileştirmeleri sayesinde TypeScript transpile süresi artık production build'lerde ihmal edilebilir seviyede. Son olarak, team scalability açısından TypeScript, cross-platform mobil projelerde kod kalitesini ve maintainability'yi önemli ölçüde artırıyor. Bu faktörler birleşince, TypeScript React Native projelerinde "nice to have" olmaktan çıkıp "must-have" haline geldi. Expo ve React Native CLI'nın varsayılan template'leri artık TypeScript ile geliyor ve community'nin büyük çoğunluğu bu standarda geçiş yaptı. ## Strict TypeScript Konfigürasyonu ile Başlamak Modern React Native projelerinde `strict: true` yeterli değil. 2026 standartları, `exactOptionalPropertyTypes` ve `noUncheckedIndexedAccess` gibi additional compiler flag'lerini de içeriyor. Bu flag'ler optional property'lerde undefined assignment'ı engelliyor ve array index erişimlerinde runtime güvenliği sağlıyor. ```json // tsconfig.json { "compilerOptions": { "strict": true, "exactOptionalPropertyTypes": true, "noUncheckedIndexedAccess": true, "moduleResolution": "bundler", "jsx": "react-jsx", "types": ["react-native/types/strict"] }, "extends": "@react-native/typescript-config/tsconfig.json" } ``` `exactOptionalPropertyTypes` flag'i, optional property'lere açıkça `undefined` atamasını yasaklar. Örneğin `interface User { name?: string }` varsa, `user.name = undefined` compile error verir. Bu, optional property ile undefined arasındaki semantic farkı korur. `noUncheckedIndexedAccess` ise array veya object index erişimlerini `T | undefined` olarak döner, böylece `array[0]` kullanımı optional chaining ya da null check gerektirir. `moduleResolution: "bundler"` ayarı, Metro bundler'ın modern module resolution stratejisini yansıtır. `react-native/types/strict` type definition'ları, React Native core API'lerinde strict typing sağlar. Bu konfigürasyon sayesinde, `Dimensions.get('window').width` gibi yaygın API'ler bile compile-time'da type-checked olur. ## React Navigation 7 ile Tip Güvenli Navigasyon React Navigation 7, parametre tiplendirmesinde major improvement getirdi. Artık her route için parametre shape'i merkezi bir type definition'da tanımlanıyor ve navigation hooks bu tipleri otomatik olarak kullanıyor. Bu sayede, bir ekrana navigate ederken yanlış parametre göndermek compile error veriyor. ```typescript // navigation/types.ts export type RootStackParamList = { Home: undefined; Profile: { userId: string }; Settings: undefined; ArticleDetail: { articleId: string; source: 'feed' | 'search' }; }; export type AppTabParamList = { Dashboard: undefined; Explore: { category?: string }; Notifications: undefined; }; ``` Bu type definition'lar, navigator oluştururken ve screen component'lerinde kullanılıyor. Screen component'leri `NativeStackScreenProps` gibi utility type'larla typed props alıyor. ```typescript // screens/ArticleDetailScreen.tsx import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import type { RootStackParamList } from '../navigation/types'; type Props = NativeStackScreenProps; export function ArticleDetailScreen({ route, navigation }: Props) { // route.params.articleId is string — guaranteed by the type // route.params.source is 'feed' | 'search' — no runtime check needed const { articleId, source } = route.params; // navigation.navigate('Profile', { userId: '123' }) — type-checked // navigation.navigate('Profile', {}) — compile error: missing userId return ( ); } ``` Bu pattern, iki kritik sorunu çözüyor. Birincisi, `route.params` artık `any` değil, exact shape'e sahip. Yani `articleId` string olarak garanti ediliyor ve runtime check'e gerek kalmıyor. İkincisi, `navigation.navigate()` çağrıları type-checked. Eğer `Profile` ekranına `userId` göndermezseniz, IDE hemen hata gösterir. > **useNavigation Hook Typing:** Eğer component'inizde `navigation` prop'u yoksa, `useNavigation>()` ile typed hook kullanabilirsiniz. Bu sayede functional component'ler de tam tip güvenliğine sahip olur. ## TurboModule Codegen ile Tip Güvenli Native Bridge New Architecture'ın en büyük kazanımlarından biri Codegen sistemi. Artık native module interface'lerini TypeScript'te tanımlıyorsunuz ve Codegen otomatik olarak iOS (C++/Objective-C++) ve Android (Java/Kotlin) binding'lerini generate ediyor. Bu sayede native taraf ile JS tarafı arasında type mismatch olamaz. ```typescript // specs/NativeDeviceInfo.ts import type { TurboModule } from 'react-native'; import { TurboModuleRegistry } from 'react-native'; export interface Spec extends TurboModule { getDeviceModel(): string; getBatteryLevel(): Promise; getStorageInfo(): Promise<{ totalBytes: number; freeBytes: number; usedPercentage: number; }>; onBatteryChange(callback: (level: number) => void): void; } export default TurboModuleRegistry.getEnforcing('DeviceInfo'); ``` Bu spec file'ı build sırasında native code generate eder. Android tarafında Kotlin implementation'ı şöyle görünür: ```kotlin // android/app/src/main/java/com/app/DeviceInfoModule.kt class DeviceInfoModule(reactContext: ReactApplicationContext) : NativeDeviceInfoSpec(reactContext) { // Return type enforced by generated NativeDeviceInfoSpec override fun getDeviceModel(): String { return Build.MODEL } override fun getBatteryLevel(): Promise { val bm = reactContext.getSystemService(Context.BATTERY_SERVICE) as BatteryManager val level = bm.getIntProperty( BatteryManager.BATTERY_PROPERTY_CAPACITY ).toDouble() return Promise.resolve(level) } } ``` `NativeDeviceInfoSpec` sınıfı Codegen tarafından otomatik generate edilir ve return type'lar TypeScript spec'teki tiplerle match etmek zorunda. Eğer `getDeviceModel()` fonksiyonu `Int` dönerse, compile error alırsınız. Bu pattern, eski `NativeModules.DeviceInfo.getDeviceModel()` gibi runtime-based API'lerin yerini alıyor ve type safety sağlıyor. Codegen aynı zamanda iOS için C++ header'ları da generate eder. Bu sayede Swift/Objective-C++ implementation'ları da type-safe hale gelir. Cross-platform native module geliştirmede bu, game-changer bir özellik. ## Generic Data Fetching ile Typed API Hook'ları API çağrıları mobile app'lerin can damarı. TanStack Query (React Query) gibi library'lerle kombine edildiğinde, TypeScript generic'leri çok güçlü abstraction'lar sağlıyor. Custom hook'lar yazarken generic type parameter'ları kullanarak, API response shape'ini type-safe hale getirebilirsiniz. ```typescript // hooks/useApiQuery.ts import { useQuery, UseQueryOptions } from '@tanstack/react-query'; interface ApiResponse { data: T; meta: { page: number; totalPages: number }; } export function useApiQuery( key: readonly string[], endpoint: string, options?: Omit>, 'queryKey' | 'queryFn'> ) { return useQuery>({ queryKey: key, queryFn: async () => { const response = await fetch(`${API_BASE}${endpoint}`); if (!response.ok) throw new ApiError(response.status); return response.json() as Promise>; }, ...options, }); } // Usage — T is inferred as Article[] interface Article { id: string; title: string; publishedAt: string; } const { data, isLoading } = useApiQuery( ['articles', 'latest'], '/articles?sort=latest' ); // data.data is Article[] — fully typed // data.meta.totalPages is number ``` Bu pattern'in gücü generic inference'ta. `useApiQuery` çağrısı yaptığınızda, TypeScript otomatik olarak `data.data` tipini `Article[] | undefined` olarak belirler. IDE'nizde autocomplete çalışır ve `data.data[0].title` gibi erişimler type-safe hale gelir. `Omit>, 'queryKey' | 'queryFn'>` kısmı, TanStack Query'nin kendi option'larını (örneğin `staleTime`, `retry`) desteklerken, `queryKey` ve `queryFn`'i hook içinde override eder. Bu sayede consumer'lar sadece business logic ile ilgili option'ları geçer. Bu hook pattern'ini mutation'lar için de kullanabilirsiniz. `useApiMutation` gibi bir hook, request body ve response type'ını type-safe hale getirir. ## Discriminated Union'lar ile State Machine Modeling Asenkron veri fetch eden screen'lerde state management karmaşık hale gelebilir: loading, error, empty, loaded gibi durumlar var. Bu durumları boolean flag'lerle yönetmek (`isLoading`, `isError`) type-safe değil çünkü invalid state kombinasyonları oluşabilir. Discriminated union'lar bu problemi elegant şekilde çözer. ```typescript // types/screen-state.ts type ScreenState = | { status: 'idle' } | { status: 'loading' } | { status: 'error'; error: string; retryCount: number } | { status: 'empty'; message: string } | { status: 'loaded'; data: T; refreshedAt: Date }; // components/DataScreen.tsx function renderContent(state: ScreenState, renderItem: (data: T) => ReactNode) { switch (state.status) { case 'idle': return null; case 'loading': return ; case 'error': // state.error is string here — TypeScript narrows automatically return ; case 'empty': return ; case 'loaded': // state.data is T — fully typed return renderItem(state.data); } } ``` Bu pattern'in avantajları çok. İlk olarak, her state branch'inde sadece ilgili field'lar mevcut. `status: 'error'` ise `state.error` garanti var, `state.data` yok. TypeScript bunu otomatik olarak narrow ediyor. İkincisi, switch-case exhaustiveness checking var. Eğer yeni bir status eklerseniz (örneğin `refetching`), switch-case eksik olduğu için compile error alırsınız. Üçüncüsü, invalid state kombinasyonları imkansız hale geliyor. `isLoading: true` ve `data: []` gibi bir durum olamaz çünkü `loading` state'inin `data` field'ı yok. Bu pattern, finite state machine prensiplerine dayanıyor ve production app'lerde bug sayısını ciddi oranda azaltıyor. > **Partial State Object Anti-Pattern:** `setState({ isLoading: true })` gibi partial update'ler discriminated union'larla çalışmaz. State transition'larını explicit şekilde yapmanız gerekir: `setState({ status: 'loading' })`. Bu başta zahmetli görünse de, uzun vadede state bug'larını minimize eder. ## React Native TypeScript Mülakat Soruları **Soru 1: Codegen sisteminin eski NativeModules API'sine göre avantajları nedir?** Codegen, TypeScript spec'ten otomatik olarak native binding'ler generate eder. Bu sayede JS-native arası type mismatch compile-time'da yakalanır. Eski NativeModules'ta `NativeModules.MyModule.someMethod()` runtime'da fail olabilirken, TurboModules build sırasında type error verir. Ayrıca Codegen, JSI üzerinden synchronous native call'lara izin verir, bu da performans iyileştirmesi sağlar. Eski Bridge mimarisinde tüm native call'lar asenkrondu ve JSON serialization overhead'i vardı. **Soru 2: `noUncheckedIndexedAccess` compiler flag'i ne işe yarar?** Bu flag, array ve object index erişimlerinde return type'ı `T | undefined` yapar. Örneğin `const arr: string[] = ['a', 'b']; const item = arr[5];` kodu, flag olmadan `item: string` döner ama runtime'da `undefined` olabilir. Flag aktifken `item: string | undefined` döner ve optional chaining (`arr[5]?.toUpperCase()`) zorunlu hale gelir. Bu, out-of-bounds erişimlerden kaynaklanan runtime crash'leri önler. **Soru 3: React Navigation'da param type'ları nasıl enforce edilir?** ParamList type'ı (`RootStackParamList`) tanımlanır ve navigator ile screen component'lerinde kullanılır. Screen component'ler `NativeStackScreenProps` generic type'ını alır. Bu sayede `route.params` exact shape'e sahip olur. `navigation.navigate()` çağrıları da type-checked olur; yanlış parametre gönderirseniz compile error alırsınız. `useNavigation` hook'u da `useNavigation>()` ile typed kullanılabilir. **Soru 4: Discriminated union pattern'inde "exhaustiveness checking" nasıl çalışır?** TypeScript, switch-case statement'larında union'ın tüm variant'larını kontrol eder. Eğer bir variant handle edilmezse, switch sonunda `default: const _exhaustiveCheck: never = state;` gibi bir check ekleyebilirsiniz. Yeni bir variant eklendiğinde bu satır compile error verir çünkü `state` artık `never` type'ına assign edilemez. Modern TypeScript (5.0+) bunu otomatik olarak implicit return type checking ile yapar. **Soru 5: TurboModules'un lazy initialization mekanizması nedir?** TurboModules, ilk kullanımda initialize edilir (lazy loading). Eski NativeModules'ta tüm native modüller app start'ta eager load edilirdi, bu da startup time'ı artırırdı. TurboModuleRegistry.get() çağrısı yapıldığında module initialize olur. Bu sayede kullanılmayan modüller memory'de yer kaplamaz. Ayrıca JSI sayesinde native module instance'ları JavaScript heap'te değil native heap'te tutulur, bu da memory overhead'ini azaltır. **Soru 6: Generic hook'larda type inference nasıl optimize edilir?** Generic parameter'ları explicit geçmek yerine, mümkün olduğunca inference kullanın. Örneğin `useApiQuery` hook'unda endpoint string'inden response type'ı çıkarılamaz, bu yüzden `` explicit geçilir. Ancak `useState` gibi hook'larda initial value'dan inference yapılabilir: `useState({ count: 0 })` otomatik olarak `{ count: number }` type'ı verir. Generic constraint'ler (``) de inference'ı kısıtlayarak yanlış tip kullanımını engeller. ## Sonuç: 2026'da React Native TypeScript Standartları React Native ekosisteminde TypeScript artık opsiyonel değil, zorunlu bir standart haline geldi. Modern projeler aşağıdaki pattern'leri benimsiyor: - **Strict compiler flag'leri:** `exactOptionalPropertyTypes` ve `noUncheckedIndexedAccess` ile runtime güvenlik - **TurboModule Codegen:** Native bridge'de compile-time type safety - **Typed navigation:** React Navigation 7 ile parametre ve route type enforcement - **Generic API hook'ları:** TanStack Query ile reusable, type-safe data fetching - **Discriminated union'lar:** State machine modeling ile invalid state'lerin önlenmesi - **JSI-based architecture:** Synchronous native call'lar ve performans optimizasyonu Bu pattern'leri benimseyen ekipler, production'da runtime error oranını %60-70 oranında düşürdü. TypeScript'in compile-time guarantees'i, mobil app geliştirmede test yükünü azaltıyor ve refactoring confidence'ını artırıyor. 2026'da React Native ile production app geliştiriyorsanız, bu mimari pattern'leri kullanmak artık best practice değil, standard gereksinim. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/react-native/react-native-typescript-type-safe-architecture