@thorprovider/types
v3.2.0
Published
Shared TypeScript types for Thor Commerce ecosystem - Framework-agnostic type definitions
Readme
@thorprovider/types
Shared TypeScript types for Thor Commerce ecosystem
Pure type definitions with zero runtime dependencies. This package provides the foundation for type-safe commerce operations across all Thor Commerce packages.
🎯 Why This Package Exists
Problem: Without shared types:
- ❌ Each package defines own types (Product in 4 places = 4x maintenance)
- ❌ Type mismatches between layers (Adapters Product ≠ Elements Product)
- ❌ Circular dependencies (adapters imports elements imports adapters)
- ❌ Violates Dependency Inversion Principle (high-level depends on low-level)
Solution: @thorprovider/types provides:
- ✅ Single Source of Truth: Product defined once, used everywhere
- ✅ Dependency Inversion: All layers depend on abstractions (SOLID DIP)
- ✅ Zero Runtime: Type-only package (0 bytes in production bundle)
- ✅ Framework Agnostic: No React/Next.js/Medusa dependencies
SOLID Compliance:
L5 (Starters) ─┐
L4 (Feature Modules) ├─→ ALL depend on ──→ @thorprovider/types (L1: Foundation)
L3 (Design System) ─┤ ↑
L2 (Infrastructure) ─┘ │
Abstractions
(Dependency Inversion)Inspired by: TypeScript's @types/* packages, tRPC (end-to-end type safety), GraphQL schemas
💰 ROI / Value Proposition
Type Safety Across Layers
// Without @thorprovider/types (each layer defines own types)
packages/adapters/src/types.ts:
interface Product { id: string; name: string; } // Missing 'handle'
packages/components/src/types.ts:
interface Product { id: string; title: string; } // Different field name!
packages/core/types.ts:
interface Product { id: number; title: string; } // Wrong type for id!
// Result: Runtime errors, bugs, inconsistencies
// With @thorprovider/types (single definition)
packages/types/src/product.ts:
export interface Product {
id: string;
handle: string;
title: string;
// ... complete, consistent definition
}
// All layers use same type → zero mismatchesMaintenance Cost Reduction
// Scenario: Add 'tags' field to Product
// Without @thorprovider/types:
1. Update adapters/types.ts: 30 min
2. Update elements/types.ts: 30 min
3. Update starters/types.ts: 30 min
4. Fix type mismatches: 2 hours
5. Update 50+ files using Product: 3 hours
= 6.5 hours per change
// With @thorprovider/types:
1. Update types/src/product.ts: 5 min
2. TypeScript errors guide changes: auto
= 5 minutes per change
// ROI: 6.5 hours → 5 min = 78x faster changesBundle Size Impact
// Type-only package: ZERO runtime cost
import type { Product } from '@thorprovider/types'; // Erased at build time
// vs. importing from package with logic:
import { Product } from '@thorprovider/adapters'; // Brings entire adapters code
// Bundle size difference: 0 KB vs 50 KB
// For 10 packages × 50 KB = 500 KB savedAI Type Inference
// AI Agent generates code with auto-complete
const product: Product = { // ← AI knows ALL fields from @thorprovider/types
id: '123',
handle: 'shirt', // ← Auto-suggested
title: 'T-Shirt', // ← Auto-suggested
// ... AI can't miss required fields
};
// Without shared types: AI guesses fields → runtime errors🤖 AI Agent Decision Framework
When to Use @thorprovider/types
✅ ALWAYS when working with commerce entities (Product, Cart, Order)
✅ Creating new packages that handle commerce data
✅ Building transformations (Medusa → unified types)
✅ Type-checking at build time (no runtime needed)
✅ Sharing types between frontend and backend
When NOT to Use
❌ Never (this is foundational layer) — always use @thorprovider/types for commerce types
⚠️ Only exception: Component-specific props (use local .props.ts files)
Decision Tree
Defining commerce data structure?
├─ YES → Is it used across packages?
│ ├─ YES → Define in @thorprovider/types ✅
│ └─ NO → Is it component-specific?
│ ├─ YES → Local .props.ts file
│ └─ NO → Still use @thorprovider/types (future reuse)
└─ NO → Is it UI-specific props?
└─ YES → Local .props.ts fileKey Rules for AI Agents
- NEVER add runtime code to @thorprovider/types (only types/interfaces)
- ALWAYS use
import typewhen importing from @thorprovider/types - DOCUMENT every field with JSDoc comments (AI needs context)
- EXTEND, don't modify existing types (add new fields, don't remove)
- FOLLOW Shopify schema for consistency (Money, Image, Connection)
Type Definition Pattern
// ALWAYS follow this pattern
/**
* Product entity representing a sellable item
* @example { id: '123', handle: 'shirt', title: 'T-Shirt' }
*/
export interface Product {
/** Unique identifier */
id: string;
/** URL-friendly slug */
handle: string;
/** Display name */
title: string;
// ... more fields with JSDoc
}When to Add New Types
// Adding new commerce entity?
// 1. Create file: packages/types/src/my-entity.ts
export interface MyEntity {
id: string;
// ... fields
}
// 2. Export from index:
export * from './my-entity';
// 3. Document in README:
// - **MyEntity**: Description here
// 4. Use across packages:
import type { MyEntity } from '@thorprovider/types';Purpose
Centralized type definitions following SOLID principles:
- Single Responsibility: Only type definitions, no logic
- Dependency Inversion: All packages depend on abstractions, not implementations
- Interface Segregation: Clean, focused interfaces
Usage
import type { Product, Cart, CartItem, Collection } from '@thorprovider/types';Included Types
- Common: Money, Image, SEO, Connection, Edge
- Product: Product, ProductVariant, ProductOption
- Cart: Cart, CartItem, CartCost
- Collection: Collection
- Customer: Customer, Address
- Order: Order, OrderItem, OrderStatus
- Auth: AuthProvider, LoginCredentials, RegisterData
Architecture
@thorprovider/types (L1: Foundation - Type Abstractions)
↓ used by
@thorprovider/adapters (Backend transformations)
↓ used by
@thorprovider/components (UI components)
↓ used by
@thorprovider/starters (Applications)All packages depend on this shared type layer, ensuring consistency across the ecosystem.
