📝 TypeScript Types Guide
Index
Available Types
Location: types/index.ts
| Type | Description | Main use |
|---|---|---|
User | Application user | Profile, auth |
Item | Generic content item | Lists, cards |
Category | Item category | Filters, navigation |
Notification | System notification | Notifications center |
StatCard | Statistics card | Dashboard |
Settings | User settings | Preferences |
Activity | Activity/event | Activity feed |
Conversation | Chat conversation | Message list |
Message | Single message | Chat |
Entity Types
User
Represents an application user.
interface User {
id: string;
name: string;
email: string;
avatar?: string;
bio?: string;
createdAt: string;
}
Usage:
const user: User = {
id: '1',
name: 'Alex Johnson',
email: 'alex@example.com',
avatar: 'https://example.com/avatar.jpg',
bio: 'Product designer & developer',
createdAt: '2024-01-15T10:00:00Z',
};
// En componentes
function ProfileCard({ user }: { user: User }) {
return (
<View>
<Avatar source={user.avatar} name={user.name} />
<Text>{user.name}</Text>
<Text>{user.email}</Text>
</View>
);
}
Item
Elemento genérico de contenido (producto, artículo, recurso, etc.).
interface Item {
id: string;
title: string;
description: string;
image?: string;
category: string;
tags: string[];
rating: number;
price?: number;
isFavorite: boolean;
createdAt: string;
}
Usage:
const item: Item = {
id: '1',
title: 'Modern UI Design System',
description: 'A comprehensive design system...',
image: 'https://example.com/image.jpg',
category: 'Design',
tags: ['UI', 'Mobile', 'System'],
rating: 4.8,
price: 49.99,
isFavorite: true,
createdAt: '2024-01-20T10:00:00Z',
};
// En componentes
function ItemCard({ item, onPress }: { item: Item; onPress: () => void }) {
return (
<TouchableOpacity onPress={onPress}>
<Image source={{ uri: item.image }} />
<Text>{item.title}</Text>
<Text>{item.category}</Text>
{item.price && <Text>${item.price}</Text>}
</TouchableOpacity>
);
}
Category
Categoría para agrupar items.
interface Category {
id: string;
name: string;
icon: string; // Nombre del icono de Lucide
color: string; // Color hex
itemCount: number;
}
Usage:
const category: Category = {
id: '1',
name: 'Technology',
icon: 'Cpu',
color: '#0A84FF',
itemCount: 24,
};
// En componentes
function CategoryChip({ category }: { category: Category }) {
const Icon = icons[category.icon];
return (
<View style={[styles.chip, { backgroundColor: category.color + '20' }]}>
<Icon size={16} color={category.color} />
<Text>{category.name}</Text>
<Text>({category.itemCount})</Text>
</View>
);
}
Notification
Notificación del sistema.
interface Notification {
id: string;
title: string;
message: string;
type: 'info' | 'success' | 'warning' | 'error';
read: boolean;
createdAt: string;
}
Usage:
const notification: Notification = {
id: '1',
title: 'New follower',
message: 'Sarah started following you',
type: 'info',
read: false,
createdAt: '2024-01-22T14:30:00Z',
};
// Colores por tipo
const notificationColors: Record<Notification['type'], string> = {
info: Colors.primary,
success: Colors.success,
warning: Colors.warning,
error: Colors.error,
};
Activity
Evento de actividad para el feed.
interface Activity {
id: string;
type: 'like' | 'comment' | 'follow' | 'mention' | 'purchase' | 'review';
userName: string;
userAvatar?: string;
message: string;
image?: string;
createdAt: string;
}
Usage:
const activity: Activity = {
id: '1',
type: 'like',
userName: 'Sarah Chen',
userAvatar: 'https://example.com/avatar.jpg',
message: 'liked your post "Modern UI Design System"',
createdAt: new Date().toISOString(),
};
// Iconos por tipo
const activityIcons: Record<Activity['type'], LucideIcon> = {
like: Heart,
comment: MessageCircle,
follow: UserPlus,
mention: AtSign,
purchase: ShoppingBag,
review: Star,
};
Conversation & Message
Para el sistema de mensajería.
interface Conversation {
id: string;
name: string;
avatar?: string;
lastMessage: string;
lastMessageTime: string;
unreadCount: number;
isOnline: boolean;
}
interface Message {
id: string;
text: string;
senderId: string;
image?: string;
createdAt: string;
status: 'sent' | 'delivered' | 'read';
}
Usage:
// Conversation list
function ConversationList({ conversations }: { conversations: Conversation[] }) {
return (
<FlatList
data={conversations}
renderItem={({ item }) => (
<ConversationRow
conversation={item}
onPress={() => router.push(`/messages/${item.id}`)}
/>
)}
/>
);
}
// Mensajes de un chat
function ChatMessages({ messages }: { messages: Message[] }) {
const currentUserId = 'current-user';
return (
<FlatList
data={messages}
renderItem={({ item }) => (
<MessageBubble
message={item}
isOwn={item.senderId === currentUserId}
/>
)}
inverted
/>
);
}
Tipos de UI
StatCard
Para tarjetas de estadísticas en dashboard.
interface StatCard {
id: string;
title: string;
value: string | number;
change?: number; // Porcentaje de cambio
icon: string; // Nombre del icono
color: string; // Color del icono
}
Settings
Configuración del usuario.
interface Settings {
notifications: boolean;
darkMode: boolean;
haptics: boolean;
language: string;
currency: string;
}
TabName
Nombres de tabs disponibles.
type TabName = 'home' | 'explore' | 'favorites' | 'profile' | 'activity' | 'messages' | 'settings';
Tipos de Estado
Para React Query
// Estado de query
interface QueryState<T> {
data: T | undefined;
isLoading: boolean;
isError: boolean;
error: Error | null;
}
// Estado de mutation
interface MutationState {
isPending: boolean;
isError: boolean;
error: Error | null;
}
Para Formularios
// Estado de formulario genérico
interface FormState<T> {
values: T;
errors: Partial<Record<keyof T, string>>;
isSubmitting: boolean;
isDirty: boolean;
}
// Ejemplo específico
interface LoginFormState {
values: {
email: string;
password: string;
};
errors: {
email?: string;
password?: string;
};
isSubmitting: boolean;
}
Extendiendo Tipos
Crear Variantes
// Tipo base
interface BaseItem {
id: string;
title: string;
createdAt: string;
}
// Extender para producto
interface Product extends BaseItem {
price: number;
stock: number;
sku: string;
}
// Extender para artículo
interface Article extends BaseItem {
content: string;
author: User;
readTime: number;
}
Usando Pick y Omit
// Solo algunos campos
type ItemPreview = Pick<Item, 'id' | 'title' | 'image'>;
// Todos menos algunos
type ItemWithoutMeta = Omit<Item, 'createdAt' | 'isFavorite'>;
// Para crear (sin id)
type CreateItemInput = Omit<Item, 'id' | 'createdAt'>;
// Para actualizar (todo parcial excepto id)
type UpdateItemInput = Partial<Omit<Item, 'id'>> & { id: string };
Usando Partial y Required
// Todo opcional
type PartialUser = Partial<User>;
// Todo requerido
type RequiredUser = Required<User>;
// Mezcla
type UserUpdate = Partial<Omit<User, 'id'>> & Required<Pick<User, 'id'>>;
Patrones Comunes
Props de Componentes
// Props básicas con style
interface BaseComponentProps {
style?: ViewStyle;
testID?: string;
}
// Extender para componente específico
interface CardProps extends BaseComponentProps {
item: Item;
onPress?: () => void;
onFavorite?: () => void;
variant?: 'default' | 'compact' | 'horizontal';
}
Handlers y Callbacks
// Handler genérico
type VoidHandler = () => void;
// Handler con parámetro
type ItemHandler = (item: Item) => void;
type IdHandler = (id: string) => void;
// Handler async
type AsyncHandler<T = void> = () => Promise<T>;
type AsyncItemHandler = (item: Item) => Promise<void>;
API Responses
// Respuesta paginada
interface PaginatedResponse<T> {
items: T[];
total: number;
page: number;
pageSize: number;
hasMore: boolean;
}
// Respuesta con cursor
interface CursorResponse<T> {
items: T[];
nextCursor?: string;
hasMore: boolean;
}
// Uso
type ItemsResponse = PaginatedResponse<Item>;
type ActivitiesResponse = CursorResponse<Activity>;
Enum-like Types
// Preferir union types sobre enums
type Status = 'idle' | 'loading' | 'success' | 'error';
type Theme = 'light' | 'dark' | 'system';
type Size = 'small' | 'medium' | 'large';
// Usar const para valores
const STATUSES = ['idle', 'loading', 'success', 'error'] as const;
type Status = typeof STATUSES[number];
Checklist de Tipos
- Usar
interfacepara objetos y props - Usar
typepara uniones y alias - Documentar campos opcionales con
? - Evitar
any- usarunknownsi es necesario - Exportar todos los tipos desde
types/index.ts - Usar
Pick,Omit,Partialpara derivar tipos - Definir tipos de respuesta de API