React Native và TypeScript năm 2026: Kiến trúc Type-Safe và Câu hỏi Phỏng vấn
Xây dựng ứng dụng React Native type-safe với TypeScript, Codegen, TurboModules, và Strict TypeScript API. Bao gồm các pattern kiến trúc, typed navigation, yêu cầu toolchain 0.87, và câu hỏi phỏng vấn.

React Native TypeScript type safety đã trưởng thành đáng kể vào giữa năm 2026, với phiên bản 0.87 biến Strict TypeScript API thành mặc định bắt buộc và hoàn thành việc hiện đại hóa toolchain toàn diện. TypeScript không còn là lớp kết nối tùy chọn giữa JavaScript và native code: nó điều khiển toàn bộ hợp đồng từ component props đến TurboModule interfaces, phát hiện sự không khớp kiểu tại thời điểm build thay vì xuất hiện trong crash logs của môi trường production.
React Native 0.87 (tháng 8/2026) biến Strict TypeScript API thành mặc định bắt buộc. Phiên bản này cũng nâng yêu cầu tối thiểu lên Node.js 22.13+, Kotlin 2.0+, và Android Gradle Plugin 9. Tùy chọn opt-out cho legacy deep imports vẫn khả dụng cho đến 0.88.
Tại sao TypeScript Hiện Là Mặc Định Cho Các Dự Án React Native
Mọi lệnh npx react-native init kể từ phiên bản 0.76 đều tạo scaffolding dự án TypeScript. Nhưng sự thay đổi thực sự xảy ra tại ranh giới native. Trước Codegen, các nhà phát triển viết type assertions thủ công khi dữ liệu di chuyển từ JavaScript sang Objective-C hoặc Kotlin, một hợp đồng stringly-typed có thể thất bại âm thầm tại runtime. Codegen đọc các file TypeScript spec và tự động sinh ra các interface C++, Objective-C++, và Java/Kotlin. Nếu TypeScript spec khai báo một method trả về number, native interface được sinh ra sẽ bắt buộc ràng buộc đó tại thời điểm compile.
Tài liệu React Native bao gồm cấu hình cơ bản, nhưng các pattern type-safe quan trọng trong production đi xa hơn: typed navigation stacks, generic API hooks, discriminated unions cho state machines, và TurboModule specs được điều khiển bởi Codegen.
Strict TypeScript API: Từ Opt-In Đến Mặc Định
Strict TypeScript API được giới thiệu trong React Native 0.80 như một tính năng opt-in. Kể từ 0.87, nó trở thành mặc định bắt buộc cho tất cả các dự án mới. Types được sinh trực tiếp từ source code của React Native thay vì được duy trì thủ công, loại bỏ sự lệch pha giữa API được tài liệu hóa và implementation thực tế.
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
"strict": true,
"exactOptionalPropertyTypes": true,
"noUncheckedIndexedAccess": true
}
}Với cấu hình này, việc import bất cứ thứ gì từ subpath như react-native/Libraries/Text/Text sẽ kích hoạt type error. Tất cả imports phải đến từ root package react-native. Nếu một thư viện hoặc codebase cũ vẫn phụ thuộc vào deep imports, có sẵn tùy chọn opt-out tạm thời cho đến 0.88:
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
"customConditions": ["react-native", "react-native-legacy-deep-imports"]
}
}Tùy chọn opt-out này sẽ bị loại bỏ trong 0.89. Việc migration nên được thực hiện trước thời điểm đó.
Yêu Cầu Toolchain Trong 0.87
React Native 0.87 nâng phiên bản tối thiểu trên toàn bộ build chain:
| Thành phần | Tối thiểu |
|---|---|
| Node.js | 22.13.0 |
| Kotlin | 2.0 (bundled: 2.2.0) |
| Android Gradle Plugin | 9.x |
| Android compileSdk | 34 (min), 37 (target) |
Đối với Android, AGP 9 yêu cầu cấu hình bổ sung:
# android/gradle.properties
android.builtInKotlin=false
android.newDsl=falseCác yêu cầu này áp dụng cho tất cả các dự án nhắm đến 0.87+. Hướng dẫn migration New Architecture bao gồm bối cảnh rộng hơn của những thay đổi này.
Type-Safe Navigation Với React Navigation 7
React Navigation 7.x cung cấp hỗ trợ TypeScript first-class. Pattern chính: định nghĩa kiểu RootStackParamList ánh xạ mọi tên screen đến params mong đợi, sau đó truyền kiểu đó qua navigators và screen components.
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 sau đó nhận typed props mà không cần casting thủ công:
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} />
);
}Cách tiếp cận này loại bỏ toàn bộ một class các runtime errors: điều hướng đến screen với params sai hoặc thiếu sẽ thất bại tại thời điểm build.
Đối với các components không phải là screen children trực tiếp, sử dụng useNavigation<NativeStackNavigationProp<RootStackParamList>>() để có được type safety tương tự mà không cần prop drilling.
Xây Dựng TurboModule Type-Safe Với Codegen
TurboModules thay thế hệ thống Native Modules cũ. File TypeScript spec đóng vai trò là nguồn sự thật duy nhất, và Codegen sinh ra các native interfaces từ nó. Nếu spec và native implementation khác nhau, build sẽ thất bại.
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');Chạy npx react-native codegen sinh ra các interface C++, Objective-C++, và Java tương ứng. Native implementation phải khớp chính xác mọi method signature. Ví dụ, getStorageInfo phải trả về object với ba trường số; trả về shape khác sẽ gây compile-time error ở phía native.
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)
}
}Cách tiếp cận này loại bỏ việc parsing ReadableMap và NSDictionary từng gây ra các bug silent type coercion trong kiến trúc cũ. Để tìm hiểu sâu hơn về hệ thống native module, xem câu hỏi phỏng vấn native modules.
Sẵn sàng chinh phục phỏng vấn React Native?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Generic Data Fetching Với Typed API Hooks
Một pattern typed hook có thể tái sử dụng tránh trùng lặp logic fetch trên các screens trong khi giữ nguyên type inference đầy đủ:
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 numberGeneric parameter T chảy qua toàn bộ chuỗi: từ điểm gọi hook, qua query function, đến component tiêu thụ kết quả. Không có as casts, không có any types.
Discriminated Unions Cho State Machines
Các trạng thái screen phức tạp (loading, error, empty, loaded) nên được mô hình hóa dưới dạng discriminated unions thay vì một tập hợp các optional fields:
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);
}
}Pattern này làm cho các impossible states không thể biểu diễn được. Trạng thái loading không thể vô tình mang theo data cũ, và trạng thái error luôn bao gồm ngữ cảnh để debug.
Một anti-pattern phổ biến: { isLoading: boolean; error?: string; data?: T }. Pattern này cho phép các trạng thái như { isLoading: true, error: 'fail', data: [...] }, ba tín hiệu mâu thuẫn cùng một lúc. Discriminated unions ngăn chặn điều này ở cấp độ type.
Câu Hỏi Phỏng Vấn React Native TypeScript
Những câu hỏi này phản ánh những gì các đội mobile engineering cấp cao hỏi trong các cuộc phỏng vấn năm 2026, khi New Architecture và TypeScript đã trở thành tiêu chuẩn.
Codegen thực thi type safety qua ranh giới JavaScript-native như thế nào?
Codegen đọc các file TypeScript (hoặc Flow) spec và sinh ra mã interface C++, Objective-C++, và Java/Kotlin. Các native interface được sinh ra thực thi chính xác các method signatures, parameter types, và return types được định nghĩa trong spec. Nếu native implementation lệch (trả về Int khi spec khai báo Double, hoặc bỏ qua một field từ struct), native compiler sẽ từ chối build. Điều này chuyển các lỗi type từ runtime crashes sang build-time failures.
Strict TypeScript API là gì và tại sao nó quan trọng?
Strict TypeScript API sinh types trực tiếp từ source code của React Native thay vì duy trì các file .d.ts viết tay. Trong 0.87, nó trở thành mặc định bắt buộc. Nó giới hạn imports đến root package react-native, deprecate deep imports. Điều này định nghĩa một API surface công khai ổn định: các refactoring nội bộ không thể phá vỡ mã consumer nếu consumers chỉ sử dụng strict types. Tùy chọn opt-out tạm thời qua customConditions vẫn khả dụng cho đến 0.88.
Cách định kiểu React Navigation params qua nested navigators như thế nào?
Định nghĩa kiểu ParamList cho mỗi navigator và kết hợp chúng bằng NavigatorScreenParams. Đối với tab navigator lồng bên trong stack, param list của stack tham chiếu đến tab's: type RootStack = { Main: NavigatorScreenParams<TabParamList>; Modal: { id: string } }. Mọi lệnh gọi navigate() sau đó được kiểm tra type qua toàn bộ hệ thống phân cấp lồng nhau, bắt tên screen sai hoặc params thiếu tại compile time.
Discriminated unions giải quyết vấn đề gì trong React Native state management?
Discriminated unions mô hình hóa các trạng thái loại trừ lẫn nhau (loading, error, loaded) như các nhánh riêng biệt của union type, được khóa bởi trường status. TypeScript thu hẹp kiểu trong mỗi nhánh của switch statement, vì vậy việc truy cập state.data chỉ có thể khi state.status === 'loaded'. Điều này ngăn chặn các impossible states như loading indicator hiển thị cùng với error data, một class bug mà optional fields và boolean flags không thể ngăn chặn.
Giải thích sự khác biệt giữa TurboModules và hệ thống Native Modules cũ.
Native Modules giao tiếp qua async bridge, serialize tất cả dữ liệu thành JSON. TurboModules sử dụng JSI (JavaScript Interface) cho các lệnh gọi C++ đồng bộ, trực tiếp mà không có serialization overhead. Chúng cũng tải lazy (khi sử dụng lần đầu thay vì khi khởi động app, giảm cold start time) và sử dụng Codegen để sinh các interface type-safe từ TypeScript specs. Hệ thống cũ dựa vào parsing ReadableMap / NSDictionary với runtime type coercion; TurboModules thực thi types tại compile time.
Những API nào đã bị loại bỏ trong React Native 0.87?
0.87 loại bỏ InteractionManager (sử dụng requestIdleCallback), các kiểu NativeMethods / NativeMethodsMixin (sử dụng HostInstance), và một số props StatusBar. Deep imports đến các đường dẫn src/private/ giờ là type errors. Cờ useTurboModules cũng đã bị loại bỏ vì TurboModules giờ luôn được bật.
Để xem thêm câu hỏi phỏng vấn React Native, hướng dẫn đầy đủ bao gồm các chủ đề về kiến trúc, hiệu suất, và debugging.
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Sources
- React Native 0.87 Release Notes - Strict TypeScript API mặc định, yêu cầu toolchain, loại bỏ API
- React Native TypeScript Documentation - Hướng dẫn thiết lập TypeScript chính thức
- React Navigation TypeScript Guide - Các pattern typed navigation
- TanStack Query Documentation - Data fetching với type inference
Điều Cần Nhớ Về React Native TypeScript Năm 2026
- Strict TypeScript API (bắt buộc trong 0.87) giới hạn imports đến API surface công khai ổn định, ngăn chặn sự phá vỡ từ các thay đổi nội bộ. Tùy chọn opt-out cho legacy deep imports chỉ khả dụng cho đến 0.88.
- Codegen sinh native interfaces từ các file TypeScript spec, chuyển các lỗi type từ runtime crashes sang build-time failures qua ranh giới JS-native
- Yêu cầu toolchain tối thiểu trong 0.87: Node.js 22.13+, Kotlin 2.0+, AGP 9, compileSdk 34+
- Typed navigation params qua
RootStackParamListvàNativeStackScreenPropsbắt tên screen sai và params thiếu trước khi app chạy - Discriminated unions mô hình hóa các trạng thái screen như các nhánh loại trừ lẫn nhau, làm cho impossible states không thể biểu diễn ở cấp độ type
- TurboModules với typed specs thay thế việc parsing
ReadableMap/NSDictionarycũ, thực thi type safety đầy đủ từ JavaScript qua C++ đến mã platform-native - Generic API hooks với TanStack Query giữ nguyên type inference từ endpoint đến component mà không cần casts thủ công
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Bạn có tìm ra lỗi trong React Native không?
Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Viết bởi
Anthony Fillion-MailletNgười sáng lập SharpSkill
Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.
Cập nhật ngày 25 tháng 8, 2026
Thẻ
Chia sẻ
Bài viết liên quan

React Native 0.85 nam 2026: Animation Backend moi, Strict TypeScript API va cau hoi phong van
React Native 0.85 gioi thieu Shared Animation Backend, kien truc post-bridge va Metro TLS. Phan tich chi tiet voi vi du code va cau hoi phong van.

Phát triển ứng dụng React Native 2026: Hướng dẫn đầy đủ và câu hỏi phỏng vấn
Hướng dẫn toàn diện về phát triển ứng dụng React Native năm 2026. Tìm hiểu về New Architecture, JSI, Fabric, TurboModules và các câu hỏi phỏng vấn thường gặp.

Kiến Trúc Mới React Native 2026: Hermes V1, Fabric, TurboModules và Bridgeless Mode
Phân tích chuyên sâu về Kiến Trúc Mới React Native trong năm 2026, bao gồm Hermes V1, Fabric Renderer, TurboModules và chế độ Bridgeless. Bài viết cung cấp các ví dụ code thực tế và câu hỏi phỏng vấn phổ biến.