TypeScript no RN: Noções Básicas
10 exemplos para você começar com TypeScript no RN - 7 básicos e 3 intermediários.
Busque em todas as páginas da documentação
10 exemplos para você começar com TypeScript no RN - 7 básicos e 3 intermediários.
Projetos Expo são configurados com TypeScript por padrão. Comece com o template em branco do TypeScript para que tsconfig.json, Metro e o pin do SDK já estejam alinhados.
npx create-expo-app@latest MyTypedApp --template blank-typescript
cd MyTypedAppConfirme os pins do SDK e do React em package.json:
{
"dependencies": {
"expo": "~57.0.4",
"react": "19.2.3",
"react-native": "0.86.0"
}
}Convenções usadas ao longo do documento:
.tsx. Arquivos .ts puros são para esquemas, clientes de API e tipos compartilhados.strict: true em tsconfig.json - o padrão quando você estende a configuração base do Expo.react-native (StyleProp, ViewStyle, GestureResponderEvent) em vez de declará-los novamente.Ferramentas: Execute
npx tsc --noEmitem CI para capturar erros de tipo antes de uma compilação nativa. Combine isso com as regras@typescript-eslintdo ESLint para variáveis não utilizadas eanyinseguro.
Estenda a configuração base publicada pelo Expo em vez de criar manualmente opções de compilador que se desviam do SDK.
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true
},
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}expo/tsconfig.base vem com o Expo SDK 57 e já define jsx, moduleResolution e os caminhos que o Metro espera.strict: true habilita strictNullChecks, noImplicitAny e flags relacionadas - capture parâmetros de rota undefined e payloads de API sem tipo precocemente..expo/types/**/*.ts captura tipos de rota gerados quando rotas tipadas são habilitadas.strict para silenciar erros - corrija o limite (props, parâmetros, fetch) ou adicione uma saída estreita com um comentário.Relacionado: Tipagem Gradual em Aplicativos Brownfield - tornando a rigidez mais estrita sem bloquear o trabalho de recursos | Rotas Tipadas do Expo Router - tipos gerados chegam em
.expo/types
Defina a forma das props de um componente como uma interface TypeScript e desestruture na 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 },
});<NomeDoComponente>Props - fácil de encontrar com pesquisa e seguro para estender mais tarde.interface para props de componentes; a fusão de declarações torna a extensão simples.React.FC - ele adiciona uma prop children implícita que você muitas vezes não quer e está caindo em desuso em 2026.Pick a partir dela.Relacionado: Tipando Componentes e Props - genéricos, uniões discriminadas e contratos de props reutilizáveis.
Marque props como opcionais com ?, então forneça valores padrão na desestruturação para que os chamadores possam omiti-las com segurança.
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?: ... torna a prop opcional; TypeScript adiciona undefined ao seu tipo.variant = "primary") preenchem quando o chamador omite a prop."primary" | "secondary") restringe os chamadores a opções válidas - o autocompletar funciona no editor.defaultProps - é obsoleto para componentes de função no React 19.Relacionado: Tipando Componentes e Props - props de variante e uniões discriminadas para campos específicos do modo.
Quando um componente aceita uma substituição de style, tipifique-o com StyleProp para que os chamadores possam passar um único objeto ou um 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" },
});
// Usage - single object or array both type-check
// <Card title="Hello" style={{ marginTop: 24 }} />
// <Card title="Hello" style={[styles.card, isActive && styles.active]} />StyleProp<ViewStyle> aceita um objeto de estilo, um array de estilos, false ou undefined - correspondendo a como o RN mescla arrays de estilos.TextStyle e ImageStyle para wrappers de texto e imagem, respectivamente; não reutilize ViewStyle em Text.[styles.card, style] para que a substituição do chamador tenha precedência sem substituir seu layout base.Pressable, tipifique style como StyleProp<ViewStyle> | ((state) => StyleProp<ViewStyle>) quando precisar de estilização de estado pressionado.Relacionado: Tipos Utilitários para RN -
StyleProp,ComponentPropse helpers seguros para estilo | Noções Básicas de Estilização -StyleSheet.createe o modelo de estilização do RN.
Deixe a inferência fazer o trabalho e adicione um genérico explícito quando o valor inicial não carregar o 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(inicial) tiver informações suficientes - useState(0) já é number.useState<User | null>(null) quando o valor puder ser mais rico posteriormente - caso contrário, o TypeScript o fixará em null.User | null tornam o estado "ainda não carregado" explícito - os consumidores devem estreitar antes de usar os campos.Relacionado: Props, Estado e Re-renders no Mobile - quando atualizações de estado acionam re-renders nativos.
Use os tipos de evento exportados do React Native para que os parâmetros do handler permaneçam tipados sem 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 é o tipo padrão para onPress, onPressIn e onPressOut em Pressable e TouchableOpacity.event.nativeEvent - a forma é estável entre iOS e Android.onPress.onLongPress da mesma forma; para TextInput, use NativeSyntheticEvent<TextInputChangeEventData>.Relacionado: Tipando Componentes e Props - props de callback e contratos de manipulador de eventos.
Derive novos tipos de tipos existentes em vez de escrever interfaces duplicadas que se desviam.
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> mantém apenas as chaves listadas; Omit<T, K> as remove - componha ambos para expressar formas de API.Partial<T> torna todas as propriedades opcionais; útil para endpoints PATCH e rascunhos de formulário.Required<T> e Readonly<T> completam os utilitários mais usados para objetos de configuração imutáveis.Relacionado: Tipos Utilitários para RN -
ComponentProps,StylePrope padrões de composição.
Tipifique os parâmetros de busca no limite da tela para que chaves ausentes ou digitadas incorretamente falhem em tempo de compilação.
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>() tipa o valor de retorno - chaves opcionais usam ? no tipo de parâmetros.Number(id) ou valide com Zod antes de usar.app/product/[id].tsx, mantenha os nomes dos parâmetros alinhados com o nome do arquivo (id corresponde a [id]).experiments.typedRoutes em app.json) para links que permaneçam sincronizados com a árvore de arquivos.Relacionado: Tipando Navegação e Parâmetros de Rota - pilhas do React Navigation e validação de parâmetros | Rotas Tipadas do Expo Router - tipos
Hrefgerados e mantê-los atualizados.
Garanta em tempo de execução que as respostas da API correspondam ao tipo TypeScript que você envia para as telas.
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> é uma mentira se você nunca validar - APIs móveis mudam sem aviso.unknown até que ela passe pelo esquema - nenhum any acidental vazando para componentes de UI.queryFn tipada.Relacionado: Tipando Respostas de API e Zod - formas de erro, composição de esquemas e caches offline.
Reutilize a superfície de props de um componente embutido ao envolver Pressable, Text ou 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 todas as props que Pressable aceita - onPress, disabled, accessibilityRole e mais.Omit<..., "children"> remove props que você substitui por sua própria API (label em vez de children de forma livre)....pressableProps por último para que os chamadores possam substituir os padrões sem listar novamente todas as props do RN.TextInput, ScrollView e componentes de terceiros que encaminham refs.Relacionado: Tipos Utilitários para RN -
ComponentProps,StylePrope padrões de composição | Tipando APIs de Módulos Nativos - conectando retornos nativos sem tipo em limites seguros de TS.
Versões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026