📝 TypeScript Types Guide

Index

  1. Available Types
  2. Entity Types
  3. UI Types
  4. State Types
  5. Extending Types
  6. Common Patterns

Available Types

Location: types/index.ts

TypeDescriptionMain use
UserApplication userProfile, auth
ItemGeneric content itemLists, cards
CategoryItem categoryFilters, navigation
NotificationSystem notificationNotifications center
StatCardStatistics cardDashboard
SettingsUser settingsPreferences
ActivityActivity/eventActivity feed
ConversationChat conversationMessage list
MessageSingle messageChat

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 interface para objetos y props
  • Usar type para uniones y alias
  • Documentar campos opcionales con ?
  • Evitar any - usar unknown si es necesario
  • Exportar todos los tipos desde types/index.ts
  • Usar Pick, Omit, Partial para derivar tipos
  • Definir tipos de respuesta de API