React Native dan TypeScript di 2026: Arsitektur Type-Safe dan Pertanyaan Wawancara

Bangun aplikasi React Native type-safe dengan TypeScript, Codegen, TurboModules, dan Strict TypeScript API. Mencakup pola arsitektur, typed navigation, persyaratan toolchain 0.87, dan pertanyaan wawancara.

React Native TypeScript Type-Safe Architecture

React Native TypeScript type safety mengalami pematangan signifikan hingga pertengahan 2026, dengan versi 0.87 menjadikan Strict TypeScript API sebagai default wajib dan menyelesaikan modernisasi toolchain secara menyeluruh. TypeScript bukan lagi pelengkap opsional antara JavaScript dan kode native: TypeScript kini mengendalikan seluruh kontrak dari component props hingga interface TurboModule, menangkap ketidakcocokan tipe pada saat build alih-alih muncul di crash logs produksi.

Perubahan di 0.87

React Native 0.87 (Agustus 2026) menjadikan Strict TypeScript API sebagai default wajib. Versi ini juga menaikkan persyaratan minimum ke Node.js 22.13+, Kotlin 2.0+, dan Android Gradle Plugin 9. Opsi opt-out untuk legacy deep imports tetap tersedia hingga 0.88 saja.

Mengapa TypeScript Kini Menjadi Default untuk Proyek React Native

Sejak versi 0.76, setiap perintah npx react-native init menghasilkan scaffolding proyek TypeScript. Namun perubahan sesungguhnya terjadi pada batas native. Sebelum Codegen, developer menulis type assertions manual ketika data berpindah dari JavaScript ke Objective-C atau Kotlin, sebuah kontrak stringly-typed yang gagal secara diam-diam saat runtime. Codegen membaca file spesifikasi TypeScript dan menghasilkan interface C++, Objective-C++, serta Java/Kotlin secara otomatis. Jika spesifikasi TypeScript mendeklarasikan method yang mengembalikan number, interface native yang dihasilkan memaksakan constraint tersebut pada saat compile time.

Dokumentasi React Native mencakup setup dasar, namun pola type-safe yang penting dalam produksi lebih mendalam: typed navigation stacks, generic API hooks, discriminated unions untuk state machines, dan TurboModule specs yang digerakkan Codegen.

Strict TypeScript API: Dari Opt-In Menjadi Default

Strict TypeScript API diperkenalkan pada React Native 0.80 sebagai fitur opt-in. Mulai versi 0.87, fitur ini menjadi default wajib untuk semua proyek baru. Types dihasilkan langsung dari source code React Native alih-alih dikelola secara manual, menghilangkan drift antara API yang terdokumentasi dan implementasi aktual.

tsconfig.json (konfigurasi default 0.87+)json
{
  "extends": "@react-native/typescript-config",
  "compilerOptions": {
    "strict": true,
    "exactOptionalPropertyTypes": true,
    "noUncheckedIndexedAccess": true
  }
}

Dengan konfigurasi ini, mengimpor apapun dari subpath seperti react-native/Libraries/Text/Text akan memicu type error. Semua import harus berasal dari root package react-native. Jika library atau codebase lama masih bergantung pada deep imports, tersedia opt-out sementara hingga 0.88:

json
{
  "extends": "@react-native/typescript-config",
  "compilerOptions": {
    "customConditions": ["react-native", "react-native-legacy-deep-imports"]
  }
}

Opt-out ini akan dihapus di 0.89. Migrasi sebaiknya dilakukan sebelum waktu tersebut.

Persyaratan Toolchain di 0.87

React Native 0.87 menaikkan versi minimum di seluruh build chain:

KomponenMinimum
Node.js22.13.0
Kotlin2.0 (bundled: 2.2.0)
Android Gradle Plugin9.x
Android compileSdk34 (min), 37 (target)

Untuk Android, AGP 9 memerlukan konfigurasi tambahan:

properties
# android/gradle.properties
android.builtInKotlin=false
android.newDsl=false

Persyaratan ini berlaku untuk semua proyek yang menargetkan 0.87+. Panduan migrasi New Architecture mencakup konteks lebih luas dari perubahan ini.

Type-Safe Navigation dengan React Navigation 7

React Navigation 7.x menyediakan dukungan TypeScript first-class. Pola kuncinya: definisikan tipe RootStackParamList yang memetakan setiap nama screen ke params yang diharapkan, kemudian teruskan tipe tersebut ke navigators dan screen components.

navigation/types.tstypescript
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;
};

Screen components kemudian menerima typed props tanpa casting manual:

screens/ArticleDetailScreen.tsxtypescript
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import type { RootStackParamList } from '../navigation/types';

type Props = NativeStackScreenProps<RootStackParamList, 'ArticleDetail'>;

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' }) is type-checked
  // navigation.navigate('Profile', {}) causes a compile error: missing userId
  return (
    <ArticleView id={articleId} referrer={source} />
  );
}

Pendekatan ini menghilangkan seluruh kategori runtime errors: navigasi ke screen dengan params yang salah atau tidak lengkap akan gagal pada saat build.

Typing hook useNavigation

Untuk komponen yang bukan children langsung dari screen, gunakan useNavigation<NativeStackNavigationProp<RootStackParamList>>() untuk mendapatkan type safety yang sama tanpa prop drilling.

Membangun TurboModule Type-Safe dengan Codegen

TurboModules menggantikan sistem Native Modules lama. File spesifikasi TypeScript berperan sebagai single source of truth, dan Codegen menghasilkan native interfaces darinya. Jika spesifikasi dan implementasi native berbeda, build akan gagal.

specs/NativeDeviceInfo.tstypescript
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  getDeviceModel(): string;
  getBatteryLevel(): Promise<number>;
  getStorageInfo(): Promise<{
    totalBytes: number;
    freeBytes: number;
    usedPercentage: number;
  }>;
  onBatteryChange(callback: (level: number) => void): void;
}

export default TurboModuleRegistry.getEnforcing<Spec>('DeviceInfo');

Menjalankan npx react-native codegen menghasilkan interface C++, Objective-C++, dan Java yang sesuai. Implementasi native harus mencocokkan setiap method signature dengan tepat. Sebagai contoh, getStorageInfo harus mengembalikan object dengan tiga field numerik; mengembalikan shape berbeda akan menyebabkan compile-time error di sisi native.

android/app/src/main/java/com/app/DeviceInfoModule.ktkotlin
class DeviceInfoModule(reactContext: ReactApplicationContext) :
    NativeDeviceInfoSpec(reactContext) {

    // Return type enforced by generated NativeDeviceInfoSpec
    override fun getDeviceModel(): String {
        return Build.MODEL
    }

    override fun getBatteryLevel(): Promise<Double> {
        val bm = reactContext.getSystemService(Context.BATTERY_SERVICE)
            as BatteryManager
        val level = bm.getIntProperty(
            BatteryManager.BATTERY_PROPERTY_CAPACITY
        ).toDouble()
        return Promise.resolve(level)
    }
}

Pendekatan ini menghilangkan parsing ReadableMap dan NSDictionary yang menyebabkan bug silent type coercion pada arsitektur lama. Untuk pembahasan lebih mendalam tentang sistem native module, lihat pertanyaan wawancara native modules.

Siap menguasai wawancara React Native Anda?

Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.

Generic Data Fetching dengan Typed API Hooks

Pola typed hook yang dapat digunakan kembali menghindari duplikasi fetch logic di berbagai screen sambil mempertahankan type inference secara penuh:

hooks/useApiQuery.tstypescript
import { useQuery, UseQueryOptions } from '@tanstack/react-query';

interface ApiResponse<T> {
  data: T;
  meta: { page: number; totalPages: number };
}

export function useApiQuery<T>(
  key: readonly string[],
  endpoint: string,
  options?: Omit<UseQueryOptions<ApiResponse<T>>, 'queryKey' | 'queryFn'>
) {
  return useQuery<ApiResponse<T>>({
    queryKey: key,
    queryFn: async () => {
      const response = await fetch(`${API_BASE}${endpoint}`);
      if (!response.ok) throw new ApiError(response.status);
      return response.json() as Promise<ApiResponse<T>>;
    },
    ...options,
  });
}

// Usage, T is inferred as Article[]
interface Article {
  id: string;
  title: string;
  publishedAt: string;
}

const { data, isLoading } = useApiQuery<Article[]>(
  ['articles', 'latest'],
  '/articles?sort=latest'
);
// data.data is Article[], fully typed
// data.meta.totalPages is number

Parameter generik T mengalir melalui seluruh chain: dari titik pemanggilan hook, melalui query function, hingga komponen yang mengonsumsi hasilnya. Tanpa as casts, tanpa any types.

Discriminated Unions untuk State Machines

State screen yang kompleks (loading, error, empty, loaded) sebaiknya dimodelkan sebagai discriminated unions alih-alih kumpulan optional fields:

types/screen-state.tstypescript
type ScreenState<T> =
  | { 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<T>(state: ScreenState<T>, renderItem: (data: T) => ReactNode) {
  switch (state.status) {
    case 'idle':
      return null;
    case 'loading':
      return <LoadingSpinner />;
    case 'error':
      // state.error is string here, TypeScript narrows automatically
      return <ErrorBanner message={state.error} retries={state.retryCount} />;
    case 'empty':
      return <EmptyState message={state.message} />;
    case 'loaded':
      // state.data is T, fully typed
      return renderItem(state.data);
  }
}

Pola ini membuat impossible states tidak dapat direpresentasikan. State loading tidak dapat secara tidak sengaja membawa data lama, dan state error selalu menyertakan konteks untuk debugging.

Hindari partial state objects

Anti-pattern yang umum: { isLoading: boolean; error?: string; data?: T }. Pola ini memungkinkan state seperti { isLoading: true, error: 'fail', data: [...] }, tiga sinyal yang saling bertentangan sekaligus. Discriminated unions mencegah hal ini pada level tipe.

Pertanyaan Wawancara React Native TypeScript

Pertanyaan-pertanyaan ini mencerminkan apa yang ditanyakan tim senior mobile engineering dalam wawancara 2026, setelah New Architecture dan TypeScript menjadi standar.

Bagaimana Codegen menegakkan type safety di batas JavaScript-native?

Codegen membaca file spesifikasi TypeScript (atau Flow) dan menghasilkan kode interface C++, Objective-C++, dan Java/Kotlin. Interface native yang dihasilkan menegakkan method signatures, parameter types, dan return types yang tepat sesuai definisi dalam spec. Jika implementasi native menyimpang (mengembalikan Int padahal spec mendeklarasikan Double, atau menghilangkan field dari struct), compiler native akan menolak build. Ini memindahkan error tipe dari runtime crashes ke build-time failures.

Apa itu Strict TypeScript API dan mengapa itu penting?

Strict TypeScript API menghasilkan types langsung dari source code React Native alih-alih memelihara file .d.ts yang ditulis tangan. Di 0.87, fitur ini menjadi default wajib. Fitur ini membatasi imports ke root package react-native, mendepresiasi deep imports. Ini mendefinisikan API surface publik yang stabil: refactoring internal tidak dapat merusak kode consumer jika consumer hanya menggunakan strict types. Opt-out sementara melalui customConditions tetap tersedia hingga 0.88.

Bagaimana cara mengetik React Navigation params di nested navigators?

Definisikan tipe ParamList per navigator dan gabungkan menggunakan NavigatorScreenParams. Untuk tab navigator yang bersarang di dalam stack, param list stack mereferensikan tab's: type RootStack = { Main: NavigatorScreenParams<TabParamList>; Modal: { id: string } }. Setiap panggilan navigate() kemudian diperiksa tipe-nya melalui seluruh hierarki nesting, menangkap nama screen yang salah atau params yang hilang pada saat compile time.

Masalah apa yang dipecahkan discriminated unions dalam React Native state management?

Discriminated unions memodelkan state yang saling eksklusif (loading, error, loaded) sebagai branch terpisah dari union type, dengan key berupa field status. TypeScript mempersempit tipe di setiap branch switch statement, sehingga mengakses state.data hanya mungkin ketika state.status === 'loaded'. Ini mencegah impossible states seperti loading indicator yang tampil bersamaan dengan error data, kategori bug yang tidak dapat dicegah oleh optional fields dan boolean flags.

Jelaskan perbedaan antara TurboModules dan sistem Native Modules lama.

Native Modules berkomunikasi melalui async bridge, men-serialize semua data ke JSON. TurboModules menggunakan JSI (JavaScript Interface) untuk panggilan C++ yang sinkron dan langsung tanpa serialization overhead. TurboModules juga memuat secara lazy (saat penggunaan pertama, bukan saat startup aplikasi, mengurangi cold start time) dan menggunakan Codegen untuk menghasilkan interface type-safe dari TypeScript specs. Sistem lama bergantung pada parsing ReadableMap / NSDictionary dengan runtime type coercion; TurboModules menegakkan types pada saat compile time.

API apa saja yang dihapus di React Native 0.87?

0.87 menghapus InteractionManager (gunakan requestIdleCallback), tipe NativeMethods / NativeMethodsMixin (gunakan HostInstance), dan beberapa props StatusBar. Deep imports ke path src/private/ kini menjadi type errors. Flag useTurboModules juga dihapus karena TurboModules kini selalu diaktifkan.

Untuk lebih banyak pertanyaan wawancara React Native, panduan lengkap mencakup topik arsitektur, performa, dan debugging.

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Sources

Yang Perlu Diingat Tentang React Native TypeScript di 2026

  • Strict TypeScript API (wajib di 0.87) membatasi imports ke API surface publik yang stabil, mencegah kerusakan akibat perubahan internal. Opt-out untuk legacy deep imports tersedia hingga 0.88 saja.
  • Codegen menghasilkan native interfaces dari file spesifikasi TypeScript, memindahkan error tipe dari runtime crashes ke build-time failures di batas JS-native
  • Minimum toolchain di 0.87: Node.js 22.13+, Kotlin 2.0+, AGP 9, compileSdk 34+
  • Typed navigation params melalui RootStackParamList dan NativeStackScreenProps menangkap nama screen yang salah dan params yang hilang sebelum aplikasi berjalan
  • Discriminated unions memodelkan state screen sebagai branch yang saling eksklusif, membuat impossible states tidak dapat direpresentasikan pada level tipe
  • TurboModules dengan typed specs menggantikan parsing ReadableMap / NSDictionary lama, menegakkan type safety penuh dari JavaScript melalui C++ ke kode platform-native
  • Generic API hooks dengan TanStack Query mempertahankan type inference dari endpoint ke komponen tanpa cast manual

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Tantangan harian

Bisakah kamu menemukan bug di React Native?

Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Anthony Fillion-Maillet

Ditulis oleh

Anthony Fillion-Maillet

Pendiri SharpSkill

Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.

Diperbarui 25 Agustus 2026

Tag

#react-native
#typescript
#mobile-development
#turbomodules
#interview

Bagikan

Artikel terkait