Conceptos Básicos de TypeScript en RN
10 ejemplos para empezar con TypeScript en RN - 7 básicos y 3 intermedios.
Busca en todas las páginas de la documentación
10 ejemplos para empezar con TypeScript en RN - 7 básicos y 3 intermedios.
Los proyectos de Expo incluyen TypeScript por defecto. Comienza desde la plantilla TypeScript en blanco para que tsconfig.json, Metro y la versión del SDK ya estén alineados.
npx create-expo-app@latest MyTypedApp --template blank-typescript
cd MyTypedAppConfirma las versiones del SDK y React en package.json:
{
"dependencies": {
"expo": "~57.0.4",
"react": "19.2.3",
"react-native": "0.86.0"
}
}Convenciones utilizadas en toda la documentación:
.tsx. Los archivos .ts simples son para esquemas, clientes de API y tipos compartidos.strict: true en tsconfig.json - el valor por defecto cuando extiendes la configuración base de Expo.react-native (StyleProp, ViewStyle, GestureResponderEvent) en lugar de redeclararlos.Herramientas: Ejecuta
npx tsc --noEmiten CI para detectar errores de tipificación antes de una compilación nativa. Combínalo con las reglas@typescript-eslintde ESLint para variables no utilizadas yanyinseguros.
Extiende la configuración base publicada de Expo en lugar de crear manualmente opciones del compilador que se desvíen del SDK.
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true
},
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}expo/tsconfig.base viene con Expo SDK 57 y ya configura jsx, moduleResolution y las rutas que Metro esperastrict: true habilita strictNullChecks, noImplicitAny y flags relacionadas - detecta temprano undefined en parámetros de ruta y payloads de API sin tipificar.expo/types/**/*.ts recoge los tipos de ruta generados cuando las rutas tipificadas están habilitadasstrict para silenciar errores - arregla el límite (props, params, fetch) o añade una puerta de escape estrecha con un comentarioRelacionado: Gradual Typing in Brownfield Apps - estrechando la tipificación sin bloquear el trabajo de funcionalidades | Expo Router Typed Routes - los tipos generados se encuentran en
.expo/types
Define la forma de las props de un componente como una interfaz TypeScript y desestructúrala en la lista de parámetros.
import { View, Text, StyleSheet } from "react-native";
interface ProfileHeaderProps {
name: string;
subtitle: string;
}
function ProfileHeader({ name, subtitle }: ProfileHeaderProps) {
return (
<View style={styles.header}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.subtitle}>{subtitle}</Text>
</View>
);
}
const styles = StyleSheet.create({
header: { padding: 16, alignItems: "center" },
name: { fontSize: 20, fontWeight: "600" },
subtitle: { fontSize: 14, color: "#6b7280", marginTop: 4 },
});<ComponentName>Props - es fácil encontrarla con búsqueda y segura para extender despuésinterface para props de componentes; la declaración de mezcla hace que extender sea directoReact.FC - añade un prop children implícito que a menudo no quieres y está cayendo en desuso en 2026Relacionado: Typing Components & Props - genéricos, uniones discriminadas y contratos de props reutilizables
Marca props opcionales con ?, y luego proporciona valores por defecto en la desestructuración para que los llamadores puedan omitirlas de forma segura.
import { Pressable, Text, StyleSheet } from "react-native";
interface ActionButtonProps {
label: string;
variant?: "primary" | "secondary";
disabled?: boolean;
onPress: () => void;
}
function ActionButton({
label,
variant = "primary",
disabled = false,
onPress,
}: ActionButtonProps) {
return (
<Pressable
style={[styles.base, variant === "primary" ? styles.primary : styles.secondary]}
disabled={disabled}
onPress={onPress}
>
<Text style={styles.label}>{label}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
base: { paddingHorizontal: 20, paddingVertical: 12, borderRadius: 8 },
primary: { backgroundColor: "#2563eb" },
secondary: { backgroundColor: "#e5e7eb" },
label: { fontWeight: "600", color: "#fff" },
});variant?: ... hace que la prop sea opcional; TypeScript añade undefined a su tipovariant = "primary") se rellenan cuando el llamador omite la prop"primary" | "secondary") restringe a los llamadores a opciones válidas - el autocompletado funciona en el editordefaultProps - está deprecado para componentes funcionales en React 19Relacionado: Typing Components & Props - props de variante y uniones discriminadas para campos específicos del modo
Cuando un componente acepta una anulación de style, tipifícalo con StyleProp para que los llamadores puedan pasar un objeto único o un array.
import { View, Text, StyleSheet, type StyleProp, type ViewStyle } from "react-native";
interface CardProps {
title: string;
style?: StyleProp<ViewStyle>;
}
function Card({ title, style }: CardProps) {
return (
<View style={[styles.card, style]}>
<Text style={styles.title}>{title}</Text>
</View>
);
}
const styles = StyleSheet.create({
card: {
margin: 16,
padding: 20,
borderRadius: 12,
backgroundColor: "#fff",
},
title: { fontSize: 18, fontWeight: "600" },
});
// Uso - un objeto único o un array ambos verifican tipo
// <Card title="Hello" style={{ marginTop: 24 }} />
// <Card title="Hello" style={[styles.card, isActive && styles.active]} />StyleProp<ViewStyle> acepta un objeto de estilo, un array de estilos, false o undefined - coincidiendo con cómo RN fusiona arrays de estilosTextStyle e ImageStyle para envoltorios de texto e imagen respectivamente; no reutilices ViewStyle en Text[styles.card, style] para que la anulación del llamador gane sin reemplazar tu disposición basePressable, tipifica style como StyleProp<ViewStyle> | ((state) => StyleProp<ViewStyle>) cuando necesitas estilos de estado presionadoRelacionado: Utility Types for RN -
StyleProp,ComponentPropsy ayudantes seguros para estilos | Styling Basics -StyleSheet.createy el modelo de estilos de RN
Deja que la inferencia haga el trabajo, y añade un genérico explícito cuando el valor inicial no contiene el tipo completo.
import { useState } from "react";
import { View, Text, ActivityIndicator, StyleSheet } from "react-native";
interface User {
id: string;
name: string;
}
export default function UserPanel() {
const [count, setCount] = useState(0);
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(false);
if (loading) {
return <ActivityIndicator style={styles.centered} />;
}
return (
<View style={styles.centered}>
<Text>Count: {count}</Text>
<Text>{user?.name ?? "No user loaded"}</Text>
</View>
);
}
const styles = StyleSheet.create({
centered: { flex: 1, justifyContent: "center", alignItems: "center" },
});useState(initial) tiene suficiente información - useState(0) ya es numberuseState<User | null>(null) cuando el valor podría ser más rico después - de lo contrario TypeScript lo fija a nullUser | null hacen que el estado "no cargado aún" sea explícito - los consumidores deben estrechar antes de usar camposRelacionado: Props, State & Re-renders on Mobile - cuándo los cambios de estado desencadenan re-renderizados nativos
Usa los tipos de eventos exportados de React Native para que los parámetros del manejador permanezcan tipificados sin any.
import { useState } from "react";
import {
Pressable,
Text,
StyleSheet,
type GestureResponderEvent,
} from "react-native";
export default function LikeButton() {
const [liked, setLiked] = useState(false);
const handlePress = (event: GestureResponderEvent) => {
setLiked((prev) => !prev);
console.log("pressed at", event.nativeEvent.pageX, event.nativeEvent.pageY);
};
return (
<Pressable
style={({ pressed }) => [styles.button, pressed && styles.pressed]}
onPress={handlePress}
>
<Text style={styles.label}>{liked ? "Liked" : "Like"}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
button: { padding: 12, borderRadius: 8, backgroundColor: "#2563eb" },
pressed: { opacity: 0.85 },
label: { color: "#fff", fontWeight: "600" },
});GestureResponderEvent es el tipo estándar para onPress, onPressIn y onPressOut en Pressable y TouchableOpacityevent.nativeEvent - la forma es estable en iOS y AndroidonPressonLongPress de la misma manera; para TextInput, usa NativeSyntheticEvent<TextInputChangeEventData>Relacionado: Typing Components & Props - props de callback y contratos de manejador de eventos
Deriva tipos nuevos de existentes en lugar de escribir interfaces duplicadas que se desvíen.
interface Device {
id: string;
name: string;
platform: "ios" | "android";
lastSeenAt: string;
}
type DeviceSummary = Pick<Device, "id" | "name">;
type NewDevice = Omit<Device, "id" | "lastSeenAt">;
type DevicePatch = Partial<Omit<Device, "id">>;Pick<T, K> mantiene solo las claves enumeradas; Omit<T, K> las elimina - compón ambas para expresar formas de APIPartial<T> hace que cada propiedad sea opcional; práctico para endpoints PATCH y borradores de formulariosRequired<T> y Readonly<T> completan las utilidades más utilizadas para objetos de configuración inmutablesRelacionado: Utility Types for RN -
ComponentProps,StylePropy ayudantes específicos de RN
Tipifica los parámetros de búsqueda en el límite de la pantalla para que las claves faltantes o mal tipificadas fallen en el tiempo de compilación.
import { View, Text, StyleSheet } from "react-native";
import { useLocalSearchParams } from "expo-router";
type ProductParams = {
id: string;
preview?: string;
};
export default function ProductScreen() {
const { id, preview } = useLocalSearchParams<ProductParams>();
return (
<View style={styles.screen}>
<Text style={styles.title}>Product {id}</Text>
{preview ? <Text style={styles.badge}>Preview mode</Text> : null}
</View>
);
}
const styles = StyleSheet.create({
screen: { flex: 1, padding: 24 },
title: { fontSize: 22, fontWeight: "600" },
badge: { marginTop: 8, color: "#2563eb" },
});useLocalSearchParams<Params>() tipifica el valor de retorno - las claves opcionales usan ? en el tipo de parámetrosNumber(id) o valida con Zod antes de usarapp/product/[id].tsx, mantén los nombres de parámetros alineados con el nombre del archivo (id coincide con [id])experiments.typedRoutes en app.json) para enlaces que se mantengan sincronizados con el árbol de archivosRelacionado: Typing Navigation & Route Params - pilas de React Navigation y validación de parámetros | Expo Router Typed Routes - tipos
Hrefgenerados y mantenerlos actualizados
Garantiza en tiempo de ejecución que las respuestas de API coincidan con el tipo de TypeScript que envías a las pantallas.
import { z } from "zod";
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
async function fetchUser(id: string): Promise<User> {
const res = await fetch(`https://api.example.com/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json: unknown = await res.json();
return UserSchema.parse(json);
}Promise<User> es una mentira si nunca validas - las APIs móviles cambian sin advertenciaunknown hasta que pase el esquema - ningún any accidental filtrando hacia componentes de UIqueryFn tipificadaRelacionado: Typing API Responses & Zod - formas de error, composición de esquemas y cachés sin conexión
Reutiliza la superficie de props de un componente integrado cuando envuelvas Pressable, Text o TextInput.
import {
Pressable,
Text,
StyleSheet,
type ComponentProps,
} from "react-native";
type PressableProps = ComponentProps<typeof Pressable>;
interface LinkButtonProps extends Omit<PressableProps, "children"> {
label: string;
}
function LinkButton({ label, style, ...pressableProps }: LinkButtonProps) {
return (
<Pressable style={[styles.link, style]} {...pressableProps}>
<Text style={styles.label}>{label}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
link: { paddingVertical: 8 },
label: { color: "#2563eb", fontWeight: "600" },
});ComponentProps<typeof Pressable> captura cada prop que Pressable acepta - onPress, disabled, accessibilityRole y másOmit<..., "children"> elimina props que reemplazas con tu propia API (label en lugar de children de forma libre)...pressableProps al final para que los llamadores puedan anular valores por defecto sin volver a enumerar cada prop de RNTextInput, ScrollView y componentes de terceros que reenvían refsRelacionado: Utility Types for RN -
ComponentProps,StylePropy patrones de composición | Typing Native Module APIs - puenteando retornos nativos sin tipificar hacia límites TS seguros
Versiones de stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0 y Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última actualización: 19 jul 2026