React Native e TypeScript nel 2026: architettura type-safe e domande da colloquio
Crea app React Native type-safe con TypeScript, Codegen, TurboModule e la Strict TypeScript API. Pattern architetturali, navigazione tipizzata, requisiti toolchain per la 0.87 e domande da colloquio.

La type safety di React Native con TypeScript è maturata in modo significativo a metà 2026: la versione 0.87 rende la Strict TypeScript API lo standard obbligatorio e completa una profonda modernizzazione della toolchain. TypeScript non è più una colla opzionale tra JavaScript e codice nativo: governa l'intero contratto, dalle props dei componenti alle interfacce dei TurboModule, intercettando le incoerenze a tempo di build invece che nei log di crash in produzione.
React Native 0.87 (agosto 2026) rende la Strict TypeScript API lo standard obbligatorio. Aumenta inoltre i requisiti minimi a Node.js 22.13+, Kotlin 2.0+ e Android Gradle Plugin 9. L'opt-out per i deep import legacy rimane disponibile solo fino alla 0.88.
Perché TypeScript è ormai lo standard per i progetti React Native
Ogni invocazione di npx react-native init dalla versione 0.76 genera lo scaffold di un progetto TypeScript. Il vero cambiamento, però, è avvenuto al confine nativo. Prima di Codegen, gli sviluppatori scrivevano asserzioni di tipo manuali nel passaggio da JavaScript a Objective-C o Kotlin: un contratto basato su stringhe che si rompeva silenziosamente a runtime. Codegen legge i file di specifica TypeScript e genera automaticamente le interfacce C++, Objective-C++ e Java/Kotlin. Se la specifica TypeScript dichiara un metodo che restituisce number, l'interfaccia nativa generata impone quel vincolo a tempo di compilazione.
La documentazione di React Native copre la configurazione di base, ma i pattern type-safe che contano in produzione vanno oltre: stack di navigazione tipizzati, hook API generici, union discriminate per le state machine e specifiche TurboModule guidate da Codegen.
La Strict TypeScript API: da opt-in a standard
La Strict TypeScript API è stata introdotta in React Native 0.80 come funzionalità opt-in. A partire dalla 0.87, è lo standard obbligatorio per tutti i nuovi progetti. I tipi vengono generati direttamente dal codice sorgente di React Native anziché essere mantenuti manualmente, eliminando le discrepanze tra l'API documentata e l'implementazione effettiva.
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
"strict": true,
"exactOptionalPropertyTypes": true,
"noUncheckedIndexedAccess": true
}
}Con questa configurazione, importare qualcosa da un sottopercorso come react-native/Libraries/Text/Text genera un errore di tipo. Tutti gli import devono provenire dal pacchetto radice react-native. Se una libreria o una codebase legacy si affida ancora ai deep import, è disponibile un opt-out temporaneo fino alla 0.88:
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
"customConditions": ["react-native", "react-native-legacy-deep-imports"]
}
}Questo opt-out verrà rimosso nella 0.89. La migrazione dovrebbe avvenire prima.
Requisiti della toolchain in 0.87
React Native 0.87 aumenta le versioni minime lungo l'intera catena di build:
| Componente | Minimo |
|---|---|
| Node.js | 22.13.0 |
| Kotlin | 2.0 (incluso: 2.2.0) |
| Android Gradle Plugin | 9.x |
| Android compileSdk | 34 (min), 37 (target) |
Per Android, AGP 9 richiede configurazione aggiuntiva:
# android/gradle.properties
android.builtInKotlin=false
android.newDsl=falseQuesti requisiti si applicano a tutti i progetti che puntano alla 0.87+. La guida alla migrazione verso la New Architecture copre il contesto più ampio di questi cambiamenti.
Navigazione type-safe con React Navigation 7
React Navigation 7.x offre un supporto TypeScript di prima classe. Il pattern chiave: definire un tipo RootStackParamList che mappa ogni nome di schermata ai parametri attesi, poi propagare quel tipo attraverso i navigatori e i componenti schermata.
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;
};I componenti schermata ricevono così props tipizzate senza cast manuali:
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 è string — garantito dal tipo
// route.params.source è 'feed' | 'search' — nessun controllo a runtime
const { articleId, source } = route.params;
// navigation.navigate('Profile', { userId: '123' }) — verificato dai tipi
// navigation.navigate('Profile', {}) — errore di compilazione: manca userId
return (
<ArticleView id={articleId} referrer={source} />
);
}Questo elimina un'intera categoria di errori a runtime: navigare verso una schermata con parametri errati o mancanti fallisce già a tempo di build.
Per i componenti che non sono figli diretti di una schermata, useNavigation<NativeStackNavigationProp<RootStackParamList>>() fornisce la stessa type safety senza prop drilling.
Costruire un TurboModule type-safe con Codegen
I TurboModule sostituiscono il vecchio sistema dei Native Modules. Il file di specifica TypeScript funge da unica fonte di verità: Codegen genera da esso le interfacce native. Se specifica e implementazione nativa divergono, la build fallisce.
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');Eseguire npx react-native codegen genera le corrispondenti interfacce C++, Objective-C++ e Java. L'implementazione nativa deve rispettare esattamente ogni firma di metodo. Ad esempio, getStorageInfo deve restituire un oggetto con tre campi numerici: restituire una forma diversa causa un errore di compilazione sul lato nativo.
class DeviceInfoModule(reactContext: ReactApplicationContext) :
NativeDeviceInfoSpec(reactContext) {
// Tipo di ritorno imposto da NativeDeviceInfoSpec generato
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)
}
}Questo approccio elimina il parsing di ReadableMap e NSDictionary che causava bug silenziosi di coercizione dei tipi nella vecchia architettura. Per un approfondimento sul sistema dei native module, consultare le domande da colloquio sui native modules.
Pronto a superare i tuoi colloqui su React Native?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Data fetching generico con hook API tipizzati
Un pattern di hook tipizzato e riutilizzabile evita di duplicare la logica di fetch tra le schermate preservando al contempo l'inferenza completa dei tipi:
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,
});
}
// Utilizzo — T viene inferito come Article[]
interface Article {
id: string;
title: string;
publishedAt: string;
}
const { data, isLoading } = useApiQuery<Article[]>(
['articles', 'latest'],
'/articles?sort=latest'
);
// data.data è Article[] — completamente tipizzato
// data.meta.totalPages è numberIl parametro generico T attraversa l'intera catena: dal punto di chiamata dell'hook, attraverso la funzione di query, fino al componente che consuma il risultato. Nessun cast as, nessun tipo any.
Union discriminate per le state machine
Gli stati complessi di una schermata, caricamento, errore, vuoto, caricato, si modellano al meglio come union discriminate, anziché come un insieme di campi opzionali:
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':
// qui state.error è string — TypeScript restringe automaticamente
return <ErrorBanner message={state.error} retries={state.retryCount} />;
case 'empty':
return <EmptyState message={state.message} />;
case 'loaded':
// state.data è T — completamente tipizzato
return renderItem(state.data);
}
}Questo pattern rende gli stati impossibili non rappresentabili. Uno stato loading non può portare accidentalmente data obsoleti e uno stato error include sempre il contesto per il debug.
Un anti-pattern comune: { isLoading: boolean; error?: string; data?: T }. Consente stati come { isLoading: true, error: 'fail', data: [...] }, tre segnali contraddittori contemporaneamente. Le union discriminate lo impediscono a livello di tipo.
Domande da colloquio su React Native e TypeScript
Queste domande riflettono ciò che i team di mobile engineering senior chiedono nei colloqui del 2026, ora che la New Architecture e TypeScript sono lo standard.
Come fa Codegen a imporre la type safety attraverso il confine JavaScript-nativo?
Codegen legge i file di specifica TypeScript (o Flow) e genera codice di interfaccia C++, Objective-C++ e Java/Kotlin. Le interfacce native generate impongono esattamente le firme dei metodi, i tipi dei parametri e i tipi di ritorno definiti nella specifica. Se l'implementazione nativa devia, restituendo Int dove la specifica dichiara Double, oppure omettendo un campo da una struct, il compilatore nativo rifiuta la build. Questo sposta gli errori di tipo dai crash a runtime ai fallimenti a tempo di build.
Cos'è la Strict TypeScript API e perché è importante?
La Strict TypeScript API genera i tipi direttamente dal codice sorgente di React Native invece di mantenere file .d.ts scritti a mano. Nella 0.87, è diventata lo standard obbligatorio. Limita gli import al pacchetto radice react-native, deprecando i deep import. Questo definisce una superficie pubblica dell'API stabile: i refactoring interni non possono rompere il codice consumer finché questo usa solo i tipi strict. Un opt-out temporaneo tramite customConditions rimane disponibile fino alla 0.88.
Come si tipizzano i parametri di React Navigation tra navigatori annidati?
Definire un tipo ParamList per ogni navigatore e comporli con NavigatorScreenParams. Per un tab navigator annidato dentro uno stack, la param list dello stack referenzia quella del tab: type RootStack = { Main: NavigatorScreenParams<TabParamList>; Modal: { id: string } }. Ogni chiamata navigate() viene così verificata dai tipi attraverso l'intera gerarchia di annidamento, intercettando nomi di schermata errati o parametri mancanti a tempo di compilazione.
Quale problema risolvono le union discriminate nello state management di React Native?
Le union discriminate modellano stati mutuamente esclusivi (caricamento, errore, caricato) come rami separati di un tipo union, distinti da un campo status. TypeScript restringe il tipo in ogni ramo di uno switch, così l'accesso a state.data è possibile solo quando state.status === 'loaded'. Questo evita stati impossibili come un indicatore di caricamento mostrato insieme a dati di errore, una categoria di bug che i campi opzionali e i flag booleani non riescono a prevenire.
Spiega la differenza tra i TurboModule e il vecchio sistema dei Native Modules.
I Native Modules comunicavano tramite la bridge asincrona, serializzando tutti i dati in JSON. I TurboModule usano JSI (JavaScript Interface) per chiamate C++ sincrone e dirette, senza overhead di serializzazione. Inoltre si caricano in modo lazy (al primo utilizzo invece che all'avvio dell'app, riducendo il tempo di cold start) e usano Codegen per generare interfacce type-safe dalle specifiche TypeScript. Il vecchio sistema si affidava al parsing di ReadableMap / NSDictionary con coercizione dei tipi a runtime; i TurboModule impongono i tipi a tempo di compilazione.
Quali API sono state rimosse in React Native 0.87?
La 0.87 ha rimosso InteractionManager (usare requestIdleCallback), i tipi NativeMethods / NativeMethodsMixin (usare HostInstance) e diverse props di StatusBar. I deep import ai percorsi src/private/ sono ora errori di tipo. È stato rimosso anche il flag useTurboModules poiché i TurboModule sono ora sempre abilitati.
Per altre domande da colloquio su React Native, la guida completa copre architettura, performance e temi di debugging.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Fonti
- React Native 0.87 Release Notes — Strict TypeScript API come standard, requisiti toolchain, rimozione API
- Documentazione TypeScript di React Native — Guida ufficiale al setup TypeScript
- Guida TypeScript di React Navigation — Pattern di navigazione tipizzata
- Documentazione TanStack Query — Data fetching con inferenza dei tipi
Da ricordare su React Native TypeScript nel 2026
- La Strict TypeScript API (obbligatoria nella 0.87) limita gli import alla superficie pubblica stabile, evitando rotture dovute a modifiche interne. L'opt-out per i deep import legacy è disponibile solo fino alla 0.88
- Codegen genera le interfacce native dai file di specifica TypeScript, spostando gli errori di tipo dai crash a runtime ai fallimenti a tempo di build attraverso il confine JS-nativo
- Requisiti minimi toolchain nella 0.87: Node.js 22.13+, Kotlin 2.0+, AGP 9, compileSdk 34+
- I parametri di navigazione tipizzati via
RootStackParamListeNativeStackScreenPropsintercettano nomi di schermata errati e parametri mancanti prima che l'app venga eseguita - Le union discriminate modellano gli stati delle schermate come rami mutuamente esclusivi, rendendo gli stati impossibili non rappresentabili a livello di tipo
- I TurboModule con specifiche tipizzate sostituiscono il vecchio parsing di
ReadableMap/NSDictionary, imponendo type safety completa da JavaScript fino al codice nativo della piattaforma passando per il C++ - Gli hook API generici con TanStack Query preservano l'inferenza dei tipi dall'endpoint al componente senza cast manuali
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Sapresti trovare il bug in React Native?
Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Scritto da
Anthony Fillion-MailletFondatore di SharpSkill
Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.
Aggiornato il 25 agosto 2026
Tag
Condividi
Articoli correlati

React Native New Architecture nel 2026: Hermes V1, Bridgeless Mode e Domande per Colloqui
Analisi approfondita della React Native New Architecture con Hermes V1, Bridgeless Mode, TurboModules e Fabric Renderer. Benchmark di performance, guida alla migrazione e domande frequenti nei colloqui tecnici.

React Native 0.87 e SwiftPM nel 2026: Build iOS Moderno e Domande per Colloqui
React Native 0.87 introduce il supporto sperimentale per Swift Package Manager, eliminando CocoaPods dalle build iOS. Questa guida copre la configurazione di SwiftPM, la Strict TypeScript API, le ottimizzazioni di Metro 0.87 e domande per colloqui di sviluppatori mobile senior.

Sviluppo App React Native 2026: Guida Completa e Domande di Colloquio
La guida completa allo sviluppo di app React Native nel 2026. JSI, Fabric, New Architecture, ottimizzazione delle performance e domande frequenti nei colloqui tecnici.