Skip to main content

TypeScript Types

The Glood Hydrogen SDK is built with TypeScript-first design, providing comprehensive type definitions for all interfaces, configurations, and data structures.

Core Configuration Types

GloodConfig

Main configuration interface for creating a Glood client.
interface GloodConfig {
  /** Glood API key for authentication */
  apiKey: string;

  /** Your Shopify domain (e.g., 'store-name.myshopify.com') */
  myShopifyDomain: string;

  /** App-specific configurations (optional - uses defaults if not provided) */
  apps?: {
    recommendations?: RecommendationsAppConfig;
    search?: SearchAppConfig;
    wishlist?: WishlistAppConfig;
  };

  /** Enable debug logging in development */
  debug?: boolean;

  /** Additional settings object */
  settings?: Record<string, any>;
}
Usage:
const config: GloodConfig = {
  apiKey: process.env.GLOOD_API_KEY!,
  myShopifyDomain: 'your-store.myshopify.com',
  debug: true,
};

PixelConfig

Configuration for pixel tracking per app.
interface PixelConfig {
  /** Enable/disable pixel tracking for this app */
  enabled: boolean;

  /** Pixel tracking endpoint */
  endpoint: string;

  /** Required consent types for pixel tracking */
  consent: readonly ConsentType[];
}
Usage:
const pixelConfig: PixelConfig = {
  enabled: true,
  endpoint: 'https://events.glood.ai',
  consent: ['analytics', 'marketing'],
};

App Configuration Types

RecommendationsAppConfig

Configuration specific to the recommendations app.
interface RecommendationsAppConfig {
  /** Main app endpoint for features and API calls */
  endpoint: string;

  /** Pixel tracking configuration */
  pixel: PixelConfig;

  /** Events this app should subscribe to (defaults to all events if not specified) */
  subscribedEvents?: EventType[];
}

SearchAppConfig

Configuration specific to the search app.
interface SearchAppConfig {
  /** Main app endpoint for features and API calls */
  endpoint: string;

  /** Pixel tracking configuration */
  pixel: PixelConfig;

  /** Events this app should subscribe to (defaults to all events if not specified) */
  subscribedEvents?: EventType[];
}

WishlistAppConfig

Configuration specific to the wishlist app.
interface WishlistAppConfig {
  /** Main app endpoint for features and API calls */
  endpoint: string;

  /** Pixel tracking configuration */
  pixel: PixelConfig;

  /** Events this app should subscribe to (defaults to all events if not specified) */
  subscribedEvents?: EventType[];
}

Client & App Types

GloodClient

The main client interface returned by createGlood().
interface GloodClient {
  /** Configuration used to create this client */
  config: GloodConfig;

  /** Debug mode enabled */
  debug: boolean;

  /** Registered apps */
  apps: Map<AppName, GloodApp>;

  /** Get all enabled apps */
  getEnabledApps(): GloodApp[];

  /** Get specific app by name */
  getApp(name: AppName): GloodApp | undefined;

  /** Add an app module to the client */
  use(appModuleOrFactory: GloodAppModule | ((config?: any) => GloodAppModule)): GloodClient;
}

GloodApp

Interface representing an individual app instance.
interface GloodApp {
  /** App name */
  name: AppName;

  /** Main app endpoint for features */
  endpoint: string;

  /** Pixel configuration */
  pixel: PixelConfig;

  /** Events this app subscribes to */
  subscribedEvents: EventType[];

  /** Analytics instance from Hydrogen useAnalytics hook */
  analytics?: any;

  /** Handle an analytics event */
  handleEvent(eventType: EventType, eventData: any, client: GloodClient): void;

  /** Set analytics instance on the app */
  setAnalytics(analytics: any): void;

  /** Update subscribed events for this app */
  setSubscribedEvents(events: EventType[]): void;
}

GloodAppModule

Function type for app module factories.
interface GloodAppModule {
  /** Create app instance with optional custom configuration */
  (): GloodApp;
}
Usage:
// App module functions return GloodAppModule
const recommendationsModule: GloodAppModule = recommendations();
const searchModule: GloodAppModule = search();
const wishlistModule: GloodAppModule = wishlist();

React Component Types

GloodProviderProps

Props for the GloodProvider React component.
interface GloodProviderProps {
  /** Glood client instance */
  client: GloodClient;

  /** Child components to wrap */
  children: React.ReactNode;

  /** Optional analytics instance (for advanced usage) */
  analytics?: any;
}
Usage:
function App() {
  return (
    <GloodProvider client={glood} loaderData={data}>
      <YourApp />
    </GloodProvider>
  );
}

Analytics Event Data Types

PageViewData

Data structure for page view events.
interface PageViewData {
  url: string;
  title?: string;
  referrer?: string;
  timestamp: number;
}

ProductViewData

Data structure for product view events.
interface ProductViewData {
  productId: string;
  productHandle: string;
  productTitle: string;
  productPrice: number;
  productVendor?: string;
  productType?: string;
  currency: string;
  timestamp: number;
}

SearchData

Data structure for search events.
interface SearchData {
  query: string;
  resultsCount: number;
  timestamp: number;
}

CollectionViewData

Data structure for collection view events.
interface CollectionViewData {
  collectionId: string;
  collectionHandle: string;
  collectionTitle: string;
  timestamp: number;
}

CartViewData

Data structure for cart view events.
interface CartViewData {
  cartId: string;
  totalPrice: number;
  itemCount: number;
  timestamp: number;
}

Pixel System Types

PixelEvent

Structure for pixel events in the transmission queue.
interface PixelEvent {
  endpoint: string;
  data: Record<string, any>;
}

PixelPayload

Complete pixel payload sent to Glood endpoints.
interface PixelPayload {
  events: Record<string, any>[];
  apiKey: string;
  shopDomain: string;
  timestamp: number;
}

Constant Types

AppName

Union type for available app names.
type AppName = 'recommendations' | 'search' | 'wishlist';
Usage:
const appName: AppName = 'recommendations'; // ✅ Valid
const invalidName: AppName = 'invalid'; // ❌ TypeScript error

EventType

Union type for all supported analytics events.
type EventType =
  | 'page_viewed'
  | 'product_viewed'
  | 'collection_viewed'
  | 'cart_viewed'
  | 'search_viewed'
  | 'search_submitted'
  | 'custom_promotion_viewed'
  | 'product_added_to_cart'
  | 'product_removed_from_cart';
Usage:
const event: EventType = 'product_viewed'; // ✅ Valid
const invalidEvent: EventType = 'invalid_event'; // ❌ TypeScript error

ConsentType

Union type for customer privacy consent types.
type ConsentType =
  | 'analytics'
  | 'marketing'
  | 'preferences'
  | 'sale_of_data';
Usage:
const consent: ConsentType[] = ['analytics', 'marketing']; // ✅ Valid
const invalidConsent: ConsentType[] = ['invalid']; // ❌ TypeScript error

Type Guards and Utilities

Type Guard Functions

Helper functions to check types at runtime:
// Check if value is a valid app name
function isAppName(value: string): value is AppName {
  return ['recommendations', 'search', 'wishlist'].includes(value);
}

// Check if value is a valid event type
function isEventType(value: string): value is EventType {
  return [
    'page_viewed',
    'product_viewed',
    'collection_viewed',
    'cart_viewed',
    'search_viewed',
    'search_submitted',
    'custom_promotion_viewed',
    'product_added_to_cart',
    'product_removed_from_cart'
  ].includes(value);
}

// Check if value is a valid consent type
function isConsentType(value: string): value is ConsentType {
  return ['analytics', 'marketing', 'preferences', 'sale_of_data'].includes(value);
}

Utility Types

Common utility types for working with the SDK:
// Extract app names from client
type EnabledApps<T extends GloodClient> = T['apps'] extends Map<infer K, any> ? K : never;

// Get app config type by name
type AppConfigType<T extends AppName> =
  T extends 'recommendations' ? RecommendationsAppConfig :
  T extends 'search' ? SearchAppConfig :
  T extends 'wishlist' ? WishlistAppConfig :
  never;

// Partial app configuration for overrides
type PartialAppConfig<T extends AppName> = Partial<AppConfigType<T>>;

Advanced TypeScript Usage

Generic App Factory

Create type-safe app factories:
function createAppFactory<T extends AppName>(
  appName: T,
  defaultConfig: AppConfigType<T>
) {
  return (config?: PartialAppConfig<T>): GloodAppModule => {
    return () => {
      // Implementation
      return {} as GloodApp;
    };
  };
}

// Usage with full type safety
const recommendationsFactory = createAppFactory('recommendations', {
  endpoint: 'https://storefront.glood.ai',
  pixel: {
    enabled: true,
    endpoint: 'https://events.glood.ai',
    consent: ['analytics', 'marketing'] as const,
  },
});

Type-Safe Configuration Builder

Build configurations with compile-time validation:
class GloodConfigBuilder {
  private config: Partial<GloodConfig> = {};

  apiKey(key: string): this {
    this.config.apiKey = key;
    return this;
  }

  shopifyDomain(domain: string): this {
    this.config.myShopifyDomain = domain;
    return this;
  }

  app<T extends AppName>(
    name: T,
    config: AppConfigType<T>
  ): this {
    if (!this.config.apps) {
      this.config.apps = {};
    }
    (this.config.apps as any)[name] = config;
    return this;
  }

  debug(enabled: boolean = true): this {
    this.config.debug = enabled;
    return this;
  }

  build(): GloodConfig {
    if (!this.config.apiKey) {
      throw new Error('API key is required');
    }
    if (!this.config.myShopifyDomain) {
      throw new Error('Shopify domain is required');
    }
    return this.config as GloodConfig;
  }
}

// Usage
const config = new GloodConfigBuilder()
  .apiKey(process.env.GLOOD_API_KEY!)
  .shopifyDomain('store.myshopify.com')
  .app('recommendations', {
    endpoint: 'https://storefront.glood.ai',
    pixel: {
      enabled: true,
      endpoint: 'https://events.glood.ai',
      consent: ['analytics'],
    },
  })
  .debug(true)
  .build();

Event Handler Typing

Type-safe event handlers:
type EventHandler<T extends EventType> = (
  eventData: T extends 'product_viewed' ? ProductViewData :
              T extends 'search_submitted' ? SearchData :
              T extends 'cart_viewed' ? CartViewData :
              Record<string, any>
) => void;

function createEventHandler<T extends EventType>(
  eventType: T,
  handler: EventHandler<T>
) {
  return (eventData: any) => {
    // Runtime validation could be added here
    handler(eventData);
  };
}

// Usage with type safety
const productViewHandler = createEventHandler('product_viewed', (data) => {
  // data is typed as ProductViewData
  console.log(`Product viewed: ${data.productTitle}`);
});

Type Imports

Import specific types as needed:
// Import all types
import type {
  GloodConfig,
  GloodClient,
  GloodApp,
  AppName,
  EventType,
  ConsentType,
  PixelConfig,
} from '@glood/hydrogen';

// Import specific app config types
import type {
  RecommendationsAppConfig,
  SearchAppConfig,
  WishlistAppConfig,
} from '@glood/hydrogen';

// Import event data types
import type {
  PageViewData,
  ProductViewData,
  SearchData,
  CartViewData,
} from '@glood/hydrogen';

// Import React component types
import type {
  GloodProviderProps,
} from '@glood/hydrogen';

Common TypeScript Patterns

Optional Configuration

Make app configurations optional with defaults:
interface OptionalGloodConfig {
  apiKey: string;
  myShopifyDomain: string;
  apps?: Partial<{
    recommendations: Partial<RecommendationsAppConfig>;
    search: Partial<SearchAppConfig>;
    wishlist: Partial<WishlistAppConfig>;
  }>;
  debug?: boolean;
}

function createGloodWithDefaults(config: OptionalGloodConfig): GloodClient {
  const fullConfig: GloodConfig = {
    ...config,
    apps: {
      recommendations: {
        endpoint: 'https://storefront.glood.ai',
        pixel: {
          enabled: true,
          endpoint: 'https://events.glood.ai',
          consent: ['analytics', 'marketing'],
        },
        ...config.apps?.recommendations,
      },
      // ... other app defaults
    },
  };

  return createGlood(fullConfig);
}

Conditional App Configuration

Configure apps based on conditions:
type ConditionalConfig<T extends boolean> = T extends true
  ? Required<GloodConfig>
  : Partial<GloodConfig>;

function createConditionalGlood<T extends boolean>(
  isProduction: T,
  config: ConditionalConfig<T>
): GloodClient {
  if (isProduction) {
    // Production requires full configuration
    return createGlood(config as Required<GloodConfig>);
  } else {
    // Development allows partial configuration
    return createGlood({
      ...config,
      debug: true,
    } as GloodConfig);
  }
}

Best Practices

1. Use Strict Types

Enable strict TypeScript settings:
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}

2. Type Imports

Use type-only imports when possible:
// ✅ Good - Type-only import
import type { GloodConfig } from '@glood/hydrogen';

// ❌ Avoid - Runtime import for types
import { GloodConfig } from '@glood/hydrogen';

3. Const Assertions

Use const assertions for literal types:
// ✅ Good - Const assertion preserves literal types
const consent = ['analytics', 'marketing'] as const;

// ❌ Avoid - Loses literal type information
const consent: ConsentType[] = ['analytics', 'marketing'];

4. Generic Constraints

Use generic constraints for type safety:
function configureApp<T extends AppName>(
  name: T,
  config: AppConfigType<T>
): void {
  // Implementation
}

// Usage is fully type-safe
configureApp('recommendations', {
  endpoint: 'https://storefront.glood.ai',
  pixel: {
    enabled: true,
    endpoint: 'https://events.glood.ai',
    consent: ['analytics', 'marketing'],
  },
});

See Also