303 lines
7.5 KiB
Markdown
303 lines
7.5 KiB
Markdown
|
|
# 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:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
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:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 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`)
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
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`)
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
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`:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"dependencies": {
|
||
|
|
"@xtablo/shared-types": "workspace:*"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
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`:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"dependencies": {
|
||
|
|
"@xtablo/shared-types": "workspace:*"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
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:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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**:
|
||
|
|
```bash
|
||
|
|
cd apps/your-app
|
||
|
|
pnpm add @xtablo/shared-types@workspace:*
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Update imports**:
|
||
|
|
```typescript
|
||
|
|
// 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:
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
✅ 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!
|
||
|
|
|