xtablo-source/docs/TYPES_PACKAGE.md
2025-11-10 08:53:03 +01:00

7.5 KiB

Types Package - @xtablo/shared-types

Overview

The @xtablo/shared-types package is a dedicated TypeScript types package that provides shared type definitions across all apps in the Xtablo monorepo. It serves as a single source of truth for all type definitions, ensuring consistency and reducing duplication.

Why a Separate Types Package?

  1. Zero Dependencies: Unlike the @xtablo/shared package which has React and other runtime dependencies, @xtablo/shared-types is pure TypeScript with zero dependencies
  2. Universal Usage: Can be used by all apps (API, frontend, mobile) without bringing in unnecessary dependencies
  3. Better Organization: Clear separation between types and implementation code
  4. Faster Builds: No runtime code means faster type checking
  5. Easy to Update: Database types can be regenerated and all apps automatically get the updates

Package Structure

packages/shared-types/
├── src/
│   ├── database.types.ts    # Supabase-generated database types (855 lines)
│   ├── events.types.ts      # Event-related domain types
│   ├── tablos.types.ts      # Tablo-related domain types
│   ├── stripe.types.ts      # Stripe integration types
│   ├── kanban.types.ts      # Kanban board types (149 lines)
│   ├── utils.ts             # Utility types (Tables, TablesInsert, etc.)
│   └── index.ts             # Main export file
├── package.json
├── tsconfig.json
├── biome.json
├── turbo.json
└── README.md

Type Categories

1. Database Types (database.types.ts)

Auto-generated from Supabase schema:

export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[];

export type Database = {
  public: {
    Tables: { /* all tables */ },
    Views: { /* all views */ },
    Functions: { /* all functions */ },
    Enums: { /* all enums */ }
  }
};

2. Utility Types (utils.ts)

Helper types for working with the database:

// Extract table row types
type Tables<TableName> = Database["public"]["Tables"][TableName]["Row"];

// Extract insert types
type TablesInsert<TableName> = Database["public"]["Tables"][TableName]["Insert"];

// Extract update types
type TablesUpdate<TableName> = Database["public"]["Tables"][TableName]["Update"];

// Remove null from types
type RemoveNull<T> = T extends null ? never : T;
type RemoveNullFromObject<T, K extends keyof T = keyof T> = {
  [L in keyof T]: L extends K ? RemoveNull<T[L]> : T[L];
};

3. Domain Types

Events (events.types.ts)

export type Event = RemoveNullFromObject<Tables<"events">, "created_at" | "end_time">;
export type EventInsert = TablesInsert<"events">;
export type EventUpdate = TablesUpdate<"events">;
export type EventInsertInTablo = Omit<EventInsert, "tablo_id">;
export type EventAndTablo = RemoveNullFromObject<...>;

Tablos (tablos.types.ts)

export type Tablo = Database["public"]["Tables"]["tablos"];
export type TabloInsert = Tablo["Insert"];
export type TabloUpdate = Tablo["Update"];
export type UserTablo = RemoveNullFromObject<...>;
export type CreateTablo = Pick<TabloInsert, ...> & { events?: EventInsertInTablo[] };

Stripe (stripe.types.ts)

All Stripe-related types including:

  • StripeSubscription, StripeProduct, StripePrice
  • SubscriptionStatus, BillingInterval
  • PriceWithProduct, SubscriptionWithDetails

Kanban (kanban.types.ts)

Complete Kanban board types:

  • KanbanTask, KanbanBoard, KanbanColumn
  • TaskStatus, Priority, TaskType
  • KanbanTaskInsert, KanbanTaskUpdate

Usage in Apps

API (apps/api)

Add to package.json:

{
  "dependencies": {
    "@xtablo/shared-types": "workspace:*"
  }
}

Usage:

import type { Event, Tablo, TablesInsert } from "@xtablo/shared-types";

// In router handlers
export async function createEvent(data: TablesInsert<"events">) {
  // Implementation
}

Frontend Apps (apps/main, apps/external)

Add to package.json:

{
  "dependencies": {
    "@xtablo/shared-types": "workspace:*"
  }
}

Usage:

import type { Event, UserTablo, StripePrice } from "@xtablo/shared-types";

interface EventCardProps {
  event: Event;
}

function EventCard({ event }: EventCardProps) {
  // Component implementation
}

Shared Package (packages/shared)

The shared package can re-export types for convenience:

// In packages/shared/src/index.ts
export type {
  Event,
  Tablo,
  UserTablo,
  StripeSubscription,
} from "@xtablo/shared-types";

Updating Database Types

When the Supabase schema changes, regenerate the types:

# Generate new types from Supabase
npx supabase gen types typescript --project-id YOUR_PROJECT_ID > packages/shared-types/src/database.types.ts

# Or if you have the Supabase CLI configured
cd packages/shared-types
supabase gen types typescript --local > src/database.types.ts

# Format the generated file
cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source
turbo run format --filter=@xtablo/shared-types

All apps will automatically get the updated types on their next build.

Advantages

Before (Duplicated Types)

apps/api/src/types/database.types.ts      (855 lines)
packages/shared/src/types/database.types.ts (855 lines)
// Types duplicated, can get out of sync

After (Single Source)

packages/shared-types/src/database.types.ts (855 lines)
// Single source, always in sync
// Used by:
//   - apps/api
//   - apps/main
//   - apps/external
//   - packages/shared
//   - xtablo-expo

Configuration Files

package.json

  • Zero dependencies (only dev dependencies for tooling)
  • Exports configuration for granular imports
  • Standard scripts: typecheck, lint, lint:fix, format

tsconfig.json

  • Strict mode enabled
  • ESNext module resolution
  • Declaration files enabled

biome.json

  • Consistent formatting rules with rest of monorepo
  • Import sorting enabled
  • Strict linting rules

turbo.json

  • Extends root configuration
  • No build step (types only)

Scripts

From the root:

# Type check the types package
turbo run typecheck --filter=@xtablo/shared-types

# Lint the types package
turbo run lint --filter=@xtablo/shared-types
turbo run lint:fix --filter=@xtablo/shared-types

# Format code
turbo run format --filter=@xtablo/shared-types

Migration Path

To migrate an app to use @xtablo/shared-types:

  1. Add dependency:

    cd apps/your-app
    pnpm add @xtablo/shared-types@workspace:*
    
  2. Update imports:

    // Before
    import type { Event } from "../types/events";
    
    // After
    import type { Event } from "@xtablo/shared-types";
    
  3. Remove local type files if they're now in @xtablo/shared-types

  4. Run type checking to ensure everything works:

    turbo run typecheck --filter=your-app
    

Best Practices

  1. Keep types pure: No runtime code, only type definitions
  2. Use utility types: Leverage Tables, TablesInsert, etc. for consistency
  3. Document complex types: Add JSDoc comments for non-obvious types
  4. Version control: Commit database type regenerations as a single commit
  5. Test changes: Run turbo run typecheck before committing type changes

Verification

All type checks pass:

✅ turbo run typecheck --filter=@xtablo/shared-types
✅ turbo run lint --filter=@xtablo/shared-types

The types package is now ready to be used across all apps in the monorepo!