# React Native và TypeScript năm 2026: Kiến trúc Type-Safe và Câu hỏi Phỏng vấn > Hướng dẫn chuyên sâu về kiến trúc type-safe trong React Native với TypeScript năm 2026: Strict API, Codegen, TurboModules, typed navigation, generic hooks và câu hỏi phỏng vấn kỹ thuật. - Published: 2026-06-16 - Updated: 2026-06-16 - Author: SharpSkill - Tags: react-native, typescript, mobile-development, turbomodules, interview - Reading time: 8 min --- Tính đến giữa năm 2026, React Native phiên bản 0.86 đã tích hợp React 19.1, Strict TypeScript API và kiến trúc bridgeless hoàn chỉnh được điều khiển bởi Codegen. TypeScript không còn đơn thuần là lớp kết nối giữa JavaScript và mã native mà đã trở thành xương sống của toàn bộ hợp đồng dữ liệu, từ props của component cho đến interface của TurboModule. Mọi sự sai lệch về kiểu dữ liệu đều được phát hiện tại thời điểm biên dịch thay vì xuất hiện trong nhật ký crash của môi trường sản xuất. Bài viết này phân tích toàn diện các mẫu thiết kế type-safe đang được áp dụng rộng rãi trong các dự án React Native chuyên nghiệp, đồng thời cung cấp câu hỏi phỏng vấn giúp lập trình viên chuẩn bị cho các vị trí phát triển mobile trong năm nay. > **Những thay đổi đáng chú ý trong năm 2026** > > React Native 0.80 giới thiệu Strict TypeScript API dạng opt-in. Phiên bản 0.82 loại bỏ vĩnh viễn legacy bridge. Phiên bản 0.85 xóa bỏ lớp interop cuối cùng. Tính đến phiên bản 0.86 (tháng 6/2026), mọi dự án mới đều bắt đầu với kiến trúc bridgeless đầy đủ và TypeScript types được sinh trực tiếp từ mã nguồn. ## Tại sao TypeScript trở thành chuẩn mặc định cho React Native Từ phiên bản 0.76, mọi lệnh `npx react-native init` đều tạo ra dự án TypeScript mặc định. Tuy nhiên, bước ngoặt thực sự xảy ra tại ranh giới giữa JavaScript và mã native. Trước khi có Codegen, các nhà phát triển phải viết type assertion thủ công khi dữ liệu đi qua lại giữa JavaScript và Objective-C hoặc Kotlin. Đây là một hợp đồng stringly-typed có thể thất bại âm thầm tại runtime mà không có bất kỳ cảnh báo nào. Codegen giải quyết triệt để vấn đề này bằng cách đọc các file TypeScript spec và tự động sinh ra interface cho C++, Objective-C++ và Java/Kotlin. Nếu TypeScript spec khai báo một phương thức trả về kiểu `number`, thì native interface được sinh ra sẽ bắt buộc ràng buộc này tại thời điểm biên dịch. [Tài liệu React Native](https://reactnative.dev/docs/typescript) cung cấp hướng dẫn cấu hình cơ bản, nhưng các mẫu thiết kế type-safe thực sự quan trọng trong môi trường production đòi hỏi nhiều hơn thế: typed navigation stacks, generic API hooks, discriminated unions cho state machines và TurboModule specs được dẫn dắt bởi Codegen. Từ góc độ kỹ thuật phần mềm, strict TypeScript giúp phát hiện hàng loạt lỗi ngay tại thời điểm biên dịch mà trước đây chỉ bộc lộ khi chạy ứng dụng trên thiết bị thực. Trong lĩnh vực mobile, nơi mỗi bản cập nhật phải trải qua quy trình review của App Store và Google Play, việc bắt lỗi sớm mang giá trị đặc biệt lớn. ## Thiết lập cấu hình Strict TypeScript API Strict TypeScript API được giới thiệu từ React Native 0.80, giới hạn phạm vi API công khai chỉ bao gồm các types được sinh trực tiếp từ mã nguồn. Điều này ngăn chặn việc vô tình phụ thuộc vào các module nội bộ có thể thay đổi giữa các phiên bản minor. ```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" } ``` Với cấu hình trên, bất kỳ lệnh import nào từ subpath như `react-native/Libraries/Text/Text` sẽ gây ra type error. Toàn bộ imports phải xuất phát từ root package `react-native`, phù hợp với chính sách deep-import deprecation được áp dụng từ phiên bản 0.80. Cờ `strict: true` kích hoạt đồng thời `strictNullChecks`, `strictFunctionTypes`, `strictBindCallApply` và nhiều kiểm tra khác. Cờ `exactOptionalPropertyTypes` ngăn việc gán giá trị `undefined` một cách tường minh cho optional property, buộc lập trình viên phân biệt rõ ràng giữa "thuộc tính không tồn tại" và "thuộc tính có giá trị undefined". Cờ `noUncheckedIndexedAccess` đảm bảo mọi truy cập mảng hoặc object bằng index đều trả về `T | undefined`, tránh lỗi runtime khi truy cập phần tử không tồn tại. ## Type-Safe Navigation với React Navigation 7 Hệ thống điều hướng (navigation) là một trong những thành phần phức tạp nhất trong ứng dụng React Native, đồng thời cũng là nơi lỗi runtime thường xuất hiện nhiều nhất. Một tham số bị thiếu, sai kiểu dữ liệu, hoặc điều hướng đến màn hình không tồn tại đều có thể gây crash. [React Navigation 7.x](https://reactnavigation.org/docs/typescript/) cung cấp hệ thống kiểu toàn diện để giải quyết triệt để vấn đề này. Bước đầu tiên là định nghĩa param list cho từng navigator: ```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; }; ``` Mỗi key trong `RootStackParamList` tương ứng với một tên màn hình, và value là kiểu của tham số mà màn hình đó nhận. Màn hình `Home` có params là `undefined`, nghĩa là không nhận tham số nào. Màn hình `ArticleDetail` yêu cầu hai tham số bắt buộc: `articleId` kiểu `string` và `source` là union type `'feed' | 'search'`. Tiếp theo, mỗi screen component sử dụng type `NativeStackScreenProps` để nhận được type-safe props: ```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 ( ); } ``` Điểm mạnh của mẫu thiết kế này nằm ở tính toàn vẹn end-to-end. Khi một màn hình điều hướng đến `ArticleDetail`, TypeScript bắt buộc phải cung cấp đúng `articleId` và `source`. Bên trong `ArticleDetailScreen`, `route.params` được định kiểu chính xác mà không cần bất kỳ kiểm tra runtime nào. Nếu sau này cần thêm hoặc bớt tham số, TypeScript sẽ báo lỗi tại tất cả các vị trí liên quan trong toàn bộ mã nguồn. > **Định kiểu cho useNavigation hook** > > Với các component không phải là screen children trực tiếp, hãy sử dụng `useNavigation>()` để đạt được type safety tương tự mà không cần prop drilling. ## Xây dựng TurboModule Type-Safe với Codegen TurboModules là cơ chế chính để truy cập API native từ JavaScript trong kiến trúc mới của React Native. Khác với Native Modules cũ sử dụng bridge dựa trên JSON, TurboModules sử dụng JSI (JavaScript Interface) để giao tiếp trực tiếp giữa JavaScript và mã native, mang lại hiệu suất vượt trội. Điều làm cho TurboModules đặc biệt liên quan đến type safety là vai trò của Codegen. Nhà phát triển viết spec module bằng TypeScript, và Codegen tự động sinh ra mã native (Java/Kotlin cho Android, Objective-C/C++ cho iOS) đảm bảo hợp đồng kiểu được tuân thủ ở cả hai phía. ```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'); ``` Interface `Spec` định nghĩa chính xác các phương thức mà module native phải triển khai: `getDeviceModel()` trả về `string` đồng bộ, `getBatteryLevel()` trả về `Promise`, `getStorageInfo()` trả về Promise với object có cấu trúc cụ thể gồm ba trường số. Codegen đọc file này và sinh ra abstract class `NativeDeviceInfoSpec` ở phía native. ```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) } } ``` Mô hình này tạo ra type safety xuyên suốt từ JavaScript đến mã native. Nếu TypeScript spec định nghĩa `getBatteryLevel()` trả về `Promise`, thì Kotlin implementation bắt buộc phải trả về `Promise`. Bất kỳ sai lệch nào đều bị phát hiện tại thời điểm biên dịch, không phải khi người dùng đang sử dụng ứng dụng. ## Generic Data Fetching với Typed API Hooks Trong các ứng dụng React Native thực tế, data fetching chiếm phần lớn logic nghiệp vụ. Việc tạo custom hook generic kết hợp [TanStack Query](https://tanstack.com/query/latest) cho phép tái sử dụng mã nguồn mà vẫn đảm bảo type safety tuyệt đối: ```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 ``` Hook `useApiQuery` sử dụng generic type parameter `T` để truyền kiểu dữ liệu xuyên suốt từ lời gọi đến kết quả trả về. Khi gọi `useApiQuery(...)`, TypeScript tự động suy luận rằng `data.data` có kiểu `Article[]` và `data.meta.totalPages` có kiểu `number`. Mọi truy cập sai tên trường hoặc sai kiểu đều được cảnh báo ngay trong trình soạn thảo. Pattern `Omit>, 'queryKey' | 'queryFn'>` cho phép người dùng hook truyền thêm các tùy chọn của TanStack Query như `staleTime`, `enabled` hay `refetchInterval` mà không ghi đè `queryKey` và `queryFn` đã được hook xử lý sẵn. ## Discriminated Unions cho State Machines Quản lý trạng thái giao diện người dùng là một trong những bài toán phức tạp nhất trong phát triển ứng dụng mobile. Một màn hình có thể ở trạng thái đang tải, lỗi, trống hoặc đã có dữ liệu, và mỗi trạng thái cần hiển thị giao diện khác nhau. Discriminated unions trong TypeScript cung cấp giải pháp an toàn và hiệu quả cho bài toán này: ```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); } } ``` Pattern discriminated union hoạt động dựa trên thuộc tính chung `status` (được gọi là discriminant). Khi TypeScript gặp `case 'error':`, nó tự động thu hẹp (narrow) kiểu của `state` thành `{ status: 'error'; error: string; retryCount: number }`. Bên trong mỗi case, chỉ các thuộc tính thuộc về trạng thái đó mới có thể truy cập được. Lợi ích lớn nhất là tính exhaustive checking. Nếu sau này bổ sung thêm trạng thái mới vào union type mà không xử lý trong câu lệnh switch, TypeScript sẽ báo lỗi biên dịch. Điều này đảm bảo không bao giờ bỏ sót bất kỳ trạng thái nào trong logic hiển thị giao diện. > **Tránh anti-pattern partial state** > > Anti-pattern phổ biến: `{ isLoading: boolean; error?: string; data?: T }`. Kiểu này cho phép tồn tại trạng thái như `{ isLoading: true, error: 'fail', data: [...] }` — ba tín hiệu mâu thuẫn cùng lúc. Discriminated unions ngăn chặn điều này ở cấp độ type system. ## Câu hỏi phỏng vấn React Native TypeScript Dưới đây là năm câu hỏi phỏng vấn phổ biến nhất về React Native và TypeScript trong năm 2026, cùng gợi ý trả lời chi tiết. **Codegen đảm bảo type safety giữa JavaScript và mã native như thế nào?** Codegen đọc các file TypeScript (hoặc Flow) spec và sinh ra mã interface cho C++, Objective-C++ và Java/Kotlin. Các native interface được sinh ra bắt buộc chữ ký phương thức, kiểu tham số và kiểu trả về phải khớp chính xác với định nghĩa trong spec. Nếu native implementation sai lệch, chẳng hạn trả về `Int` khi spec khai báo `Double` hoặc thiếu trường trong struct, native compiler sẽ từ chối build. Cơ chế này chuyển lỗi kiểu từ runtime crash sang build-time failure. **Strict TypeScript API là gì và tại sao nó quan trọng?** Được giới thiệu từ React Native 0.80, Strict TypeScript API sinh types trực tiếp từ mã nguồn của React Native thay vì duy trì các file `.d.ts` viết tay. Nó giới hạn imports chỉ đến root package `react-native`, loại bỏ deep imports. Điều này xác định một API surface ổn định — các thao tác refactoring nội bộ không thể làm hỏng mã của consumer nếu consumer chỉ sử dụng strict types. Kích hoạt bằng cách thêm `"types": ["react-native/types/strict"]` vào `tsconfig.json`. **Làm thế nào để đảm bảo type safety cho navigation params trong deep linking?** React Navigation 7 cho phép khai báo linking config cùng kiểu với `RootStackParamList`. Khi định nghĩa `linking.config.screens`, TypeScript kiểm tra rằng mỗi tên màn hình và hàm parse cho params đều khớp với type đã khai báo. Đối với deep link URL như `/article/123?source=feed`, hàm parse phải trả về object đúng kiểu `{ articleId: string; source: 'feed' | 'search' }`. Kết hợp với Zod schema validation cho runtime, hệ thống đạt được type safety ở cả hai cấp độ: biên dịch và thực thi. **Giải thích cách discriminated unions cải thiện state management trong React Native.** Discriminated unions mô hình hóa mỗi trạng thái có thể có của một màn hình dưới dạng union type với thuộc tính discriminant. TypeScript tự động narrow kiểu dựa trên discriminant, đảm bảo mã nguồn chỉ truy cập các thuộc tính hợp lệ cho từng trạng thái. Quan trọng hơn, TypeScript kiểm tra tính đầy đủ (exhaustiveness) — nếu thêm trạng thái mới mà không xử lý trong switch, trình biên dịch sẽ báo lỗi. Pattern này loại bỏ hoàn toàn các lỗi "impossible state" vốn rất phổ biến khi sử dụng nhiều biến boolean riêng lẻ. **TurboModules khác gì so với hệ thống Native Modules cũ?** Native Modules giao tiếp qua async bridge, serialize toàn bộ dữ liệu thành JSON. TurboModules sử dụng JSI (JavaScript Interface) cho các lời gọi C++ trực tiếp và đồng bộ, không có serialization overhead. TurboModules cũng được tải lazy (chỉ khi sử dụng lần đầu thay vì lúc khởi động ứng dụng, giảm thời gian cold start) và sử dụng Codegen để sinh interface type-safe từ TypeScript specs. Hệ thống cũ dựa vào việc parse `ReadableMap` / `NSDictionary` với type coercion tại runtime; TurboModules bắt buộc kiểu tại thời điểm biên dịch. Để tìm hiểu thêm về [câu hỏi phỏng vấn React Native](/technologies/react-native/interview-questions/rn-native-modules), phần native modules chuyên sâu bao gồm JSI, Fabric và kiến trúc bridgeless chi tiết. ## Kết luận React Native kết hợp TypeScript trong năm 2026 không chỉ là xu hướng mà đã trở thành nền tảng kỹ thuật bắt buộc cho các dự án mobile chuyên nghiệp. Dưới đây là tóm tắt các điểm quan trọng: - **Strict TypeScript API (0.80+)** giới hạn imports vào API surface ổn định, ngăn chặn lỗi phát sinh từ các thay đổi nội bộ của React Native. Nên kích hoạt cho mọi dự án mới - **Codegen** sinh native interface từ TypeScript spec, chuyển lỗi kiểu từ runtime crash sang build-time failure xuyên suốt ranh giới JS-native - **Typed navigation params** thông qua `RootStackParamList` và `NativeStackScreenProps` phát hiện tên màn hình sai hoặc thiếu tham số trước khi ứng dụng chạy - **Discriminated unions** mô hình hóa trạng thái màn hình thành các nhánh loại trừ lẫn nhau, loại bỏ hoàn toàn các "impossible state" ở cấp độ type system - **TurboModules với typed specs** thay thế hệ thống parse `ReadableMap` / `NSDictionary` cũ, đảm bảo type safety đầy đủ từ JavaScript qua C++ đến mã native của từng nền tảng - **Generic API hooks** với [TanStack Query](https://tanstack.com/query/latest) bảo toàn suy luận kiểu từ endpoint đến component mà không cần ép kiểu thủ công --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/vi/blog/react-native/react-native-typescript-type-safe-architecture