Los genéricos, las uniones discriminadas y los contratos de props reutilizables convierten los componentes de React Native en APIs autodocumentadas. Los tipos de props fuertes capturan combinaciones inválidas en tiempo de compilación - antes de que aparezcan como bugs de layout en iOS y Android.
Tarjeta de referencia rápida - lista para copiar y pegar.
import { Pressable, StyleSheet, Text, View, type ViewProps } from "react-native";// Contrato base reutilizable - layout compartido + testIDtype BoxProps = ViewProps & { testID?: string;};// Unión discriminada - solo combinaciones de props válidas se compilantype StatusBadgeProps = | { variant: "success"; message: string } | { variant: "error"; message: string; onRetry: () => void } | { variant: "loading" };export function StatusBadge(props: StatusBadgeProps) { if (props.variant === "loading") { return <Text style={styles.muted}>Cargando…</Text>; } if (props.variant === "error") { return ( <View style={styles.row}> <Text style={styles.error}>{props.message}</Text> <Pressable onPress={props.onRetry}> <Text style={styles.link}>Reintentar</Text> </Pressable> </View> ); } return <Text style={styles.success}>{props.message}</Text>;}// Fila de lista genérica - T fluye del caller a renderItemtype ListProps<T> = BoxProps & { data: readonly T[]; keyExtractor: (item: T) => string; renderItem: (item: T) => React.ReactNode;};export function SimpleList<T>({ data, keyExtractor, renderItem, ...viewProps }: ListProps<T>) { return ( <View {...viewProps}> {data.map((item) => ( <View key={keyExtractor(item)}>{renderItem(item)}</View> ))} </View> );}
Cuándo usarlo: Estás construyendo primitivos de UI compartidos, filas de listas o componentes impulsados por variantes y quieres que TypeScript rechace combinaciones de props imposibles antes de la ejecución.
import type { ComponentProps, ReactElement, ReactNode } from "react";import { Pressable, Text, type TextProps, type ViewProps } from "react-native";// Hereda props primitivos, sobrescribe solo lo que poseestype CardProps = ViewProps & { title: string; footer?: ReactNode;};// Extrae onPress de Pressable sin importar manualmente el tipo de valortype IconButtonProps = Pick<ComponentProps<typeof Pressable>, "onPress" | "disabled"> & { label: string; icon: ReactElement;};// Children estrictos - solo nodos Text permitidos dentro de un envoltorio de tipografíatype TypographyProps = TextProps & { children: string | ReactElement<typeof Text>;};
Opcional todo en props de variante - { variant?: "a" \| "b"; a?: string; b?: number } deja que los callers pasen { variant: "a", b: 1 } sin error. Solución: Usa una unión discriminada con campos requeridos por rama.
Duplicar tipos onPress - Escribir a mano (event: GestureResponderEvent) => void se desvía de las actualizaciones de RN. Solución: Usa PressableProps["onPress"] o ComponentProps<typeof Pressable>["onPress"].
Conversión de datos de lista genérica - data as Place[] dentro de una lista compartida oculta errores del caller. Solución: Empuja el genérico al componente de lista: FlatList<Place>, SectionList<Place>.
Expandiendo props desconocidos sobre View - {...rest} de un tipo amplio puede pasar claves inválidas a vistas nativas. Solución:Omit de claves conocidas y tipifica rest como ViewProps o una selección estrecha.
Tipos de objeto inline en cada componente - ({ name }: { name: string }) está bien una vez; las formas repetidas pertenecen a un tipo nombrado. Solución: Exporta ProfileCardProps desde el mismo archivo que el componente.
Olvidar readonly en arrays - Props tipificados como T[] permiten que los callers hagan .push() en arrays pasados. Solución: Prefiere readonly T[] para props de datos de solo lectura.
Usar React.FC para código nuevo - children implícitos y peculiaridades heredadas añaden ruido en React 19. Solución: Tipifica el parámetro de props directamente en una función nombrada.
¿Debería usar interface o type para props de componente?
Ambas funcionan. Usa interface cuando esperes fusión de declaraciones o extensión entre archivos; usa type para uniones, tipos mapeados y composiciones Omit/Pick. La consistencia dentro de un sistema de diseño importa más que la palabra clave.
¿Cómo tipifica children en componentes de función de React 19?
Añade children?: React.ReactNode a tu tipo de props cuando el componente renderiza una ranura. No confíes en React.FC - ya no es el valor predeterminado recomendado. Para APIs más estrictas, estrecha a ReactElement o a un tipo de componente específico.
¿Cuál es el tipo correcto para props de estilo?
Usa StyleProp<ViewStyle> en View, StyleProp<TextStyle> en Text, y StyleProp<ImageStyle> en Image. Estos aceptan un objeto de estilo, arrays y entradas falsas condicionales (condition && styles.x).
¿Cómo se estrechan las uniones discriminadas dentro de JSX?
Estrecha en el cuerpo de la función con if (props.variant === "error") antes de retornar JSX. TypeScript lleva el tipo estrechado a esa rama, así que props.onRetry solo es requerido cuando variant es "error".
¿Cómo comparto props entre dos componentes similares?
Extrae un tipo base (RowBaseProps) e intersecta con tipos específicos de variante. Usa Pick y Omit para reutilizar porciones de primitivos: Pick<PressableProps, "onPress" | "disabled">.
¿Cómo tipifica un renderItem genérico de FlatList?
item se infiere como Place sin conversiones manuales.
¿Debería exportar tipos de props desde archivos de componentes?
Exporta cuando otros módulos envuelven o extienden el componente - pantallas de navegación, historias de Storybook y helpers de prueba se benefician de export type ListRowProps. Mantén props de helper interno sin exportar.
¿Cómo tipifica props de callback opcionales?
Usa campos opcionales: onPress?: () => void. Cuando el callback es requerido solo para una rama de unión, ponlo dentro de esa rama de una unión discriminada en lugar de marcarlo como opcional globalmente.
Trampa común: ¿Por qué expandir props rompe el autocompletado?
{...rest} donde rest se tipifica demasiado ampliamente (p. ej. Record<string, unknown>) pierde verificación de claves. Tipifica rest como Omit<CardProps, "title"> o ViewProps para que solo las claves nativas válidas se expandan.
¿Cómo tipifica uniones de nombres de icono?
Usa uniones de literales de cadena ("star" | "pin") o mapas as const:
Las uniones literales capturan errores tipográficos en tiempo de compilación e impulsan exhaustividad de switch.
¿Puedo usar valores de parámetro predeterminado con props tipificados?
Sí - function Counter({ initial = 0 }: { initial?: number }) es idiomático. Los valores predeterminados se aplican en tiempo de ejecución; TypeScript aún trata la prop como opcional en el lado del caller.
¿Cómo tipifica children de render-prop?
type MeasureProps = { children: (size: { width: number; height: number }) => React.ReactNode;};
El retorno del callback debe ser ReactNode; usa ReactElement solo cuando requieras un único elemento.
¿Cómo afecta la verificación estricta de null a las props?
Con strict: true, las props opcionales son T | undefined. Usa prop ?? fallback o guardias explícitos. Evita aserciones de non-null prop! en componentes - los callers pueden omitir el campo.
¿Deberían los componentes de fila de lista usar memo con props tipificados?
Sí, cuando las filas son costosas y reciben props estables. Empareja memo con un tipo de props nombrado para que los comparadores y pruebas permanezcan claros. Las lambdas inline inestables onPress={() => …} anulan la memoización.
¿Cómo extiendo props de componentes de terceros?
Usa ComponentProps<typeof ThirdPartyButton> o el tipo de props exportado del paquete. Re-exporta una versión estrechada con Omit si ocultas algunas props aguas arriba de tu sistema de diseño.