> ## Documentation Index
> Fetch the complete documentation index at: https://www.commercengine.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Type Safety

> 100% type-safe SDK with IntelliSense, compile-time checking, and OpenAPI-generated types

The SDK provides **100% type safety** with auto-generated types from OpenAPI specifications, complete IntelliSense support, and compile-time error prevention.

## Why Type Safety Matters

<CardGroup cols={2}>
  <Card title="IntelliSense Support" icon="lightbulb-on">
    Complete autocomplete for all API methods, parameters, and response data
  </Card>

  <Card title="Compile-time Checking" icon="shield">
    Catch errors during development, not at runtime
  </Card>

  <Card title="Self-Documenting Code" icon="book">
    Types serve as always up-to-date documentation
  </Card>

  <Card title="Refactoring Safety" icon="code">
    Confidently refactor with IDE support for finding all usages
  </Card>
</CardGroup>

## Auto-Generated Types

All types are **automatically generated** from the OpenAPI specification, ensuring they're always in sync with the API:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Import response types (for reading API responses)
import type {
  GetProductDetailContent,
  GetCartContent,
  GetOrderDetailContent,
  GetUserDetailContent,
  ApiResult
} from '@commercengine/storefront';

// Import Input types (for request bodies)
import type {
  CustomerAddressInput,
  UpdateFulfillmentPreferenceBody,
} from '@commercengine/storefront';
```

### Response Types vs Input Types

The SDK exports **context-aware types** to distinguish between data you *read* from the API and data you *send* to the API:

| Type name         | Used for                 | Example                                       |
| ----------------- | ------------------------ | --------------------------------------------- |
| `SchemaName`      | Response data (reading)  | `CustomerAddress`, `Cart`, `Product`          |
| `SchemaNameInput` | Request bodies (writing) | `CustomerAddressInput`, `AnalyticsEventInput` |

Some schemas appear only in responses, some only in request bodies, and some in both. The SDK generates the right exports automatically:

* **Response-only schemas** — export the base name only (e.g. `Cart`)
* **Request + response schemas** — export both (e.g. `CustomerAddress` + `CustomerAddressInput`)
* **Request-only schemas** — export the `Input` name only (e.g. `AnalyticsEventInput`)

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Response data — use the base name
const address: CustomerAddress = response.data.address;

// Request body — use the Input suffix
const newAddress: CustomerAddressInput = {
  street: "123 Main St",
  city: "New York",
  // ...
};
const { data, error } = await sdk.customer.createAddress(newAddress);
```

<Tip>
  You can also use the endpoint-level `Body` types (e.g. `UpdateFulfillmentPreferenceBody`) to type the full request body shape passed to an SDK method.
</Tip>

### The `{ data, error }` Pattern

Every API operation returns a type-safe object with `data` and `error` properties:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Type signature automatically inferred from OpenAPI spec
const { data, error } = await client.catalog.getProductDetail({ product_id_or_slug: 'product-id' });

if (data) {
  // TypeScript knows data.product is a ProductDetail
  const product = data.product;
  console.log(product.id);           // ✅ string
  console.log(product.name);         // ✅ string
  console.log(product.slug);         // ✅ string
  console.log(product.description);  // ✅ string
} else if (error) {
  // TypeScript knows error is ApiErrorResponse
  console.log(error.message); // ✅ string
  console.log(error.code);    // ✅ string
}
```

## IntelliSense in Action

### Method Parameters

Complete autocomplete for all API parameters with OpenAPI-generated types:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// IntelliSense shows all available options from OpenAPI spec
const { data: productsData, error } = await client.catalog.listProducts({
  limit: 20,                    // ✅ number | undefined
  category_id: 'electronics',   // ✅ string | undefined
  sort_by: 'name',             // ✅ string | undefined  
  min_price: 100,              // ✅ number | undefined
  max_price: 500               // ✅ number | undefined
});
```

### Response Data Access

Full type safety when accessing response data:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
if (productsData) {
  productsData.products.forEach(product => {
    // Full IntelliSense for auto-generated Product schema
    product.id;              // ✅ string
    product.name;            // ✅ string
    product.slug;            // ✅ string
    product.description;     // ✅ string
    product.short_description; // ✅ string | null
    product.is_active;       // ✅ boolean

    // TypeScript prevents accessing non-existent properties
    product.nonExistent;     // ❌ Compile error
  });
}
```

### Cart Operations

Type-safe cart management with correct API structure:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Creating cart with typed item structure from OpenAPI
const { data, error } = await client.cart.createCart({
  items: [{
    product_id: 'prod_123',    // ✅ string (required)
    variant_id: null,          // ✅ string | null (required)
    quantity: 2                // ✅ number (required)
  }]
});

if (data) {
  const cart = data.cart;
  // Cart object with full type safety from OpenAPI schema
  cart.id;                    // ✅ string
  cart.cart_items;            // ✅ CartItem[]
  cart.grand_total;           // ✅ number
  cart.currency;              // ✅ string
  cart.shipping_address;      // ✅ object | null
}
```

## Advanced Type Features

### Discriminated Unions

Type-safe handling of different response states:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// The { data, error } pattern with proper error handling
const { data, error } = await client.auth.loginWithEmail({
  email: 'user@example.com',
  register_if_not_exists: true
});

if (data) {
  // TypeScript knows data contains the success response
  data.otp_token;  // ✅ string
  data.otp_action; // ✅ string
} else if (error) {
  // TypeScript knows error contains error information
  error.message; // ✅ string
  error.code;    // ✅ string
}
```

### Generic Type Constraints

Type-safe configuration with OpenAPI-generated interfaces:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// TokenStorage interface is properly typed
interface TokenStorage {
  getAccessToken(): Promise<string | null>;
  setAccessToken(token: string): Promise<void>;
  getRefreshToken(): Promise<string | null>;
  setRefreshToken(token: string): Promise<void>;
  clearTokens(): Promise<void>;
}

// Implementation must satisfy interface
class CustomTokenStorage implements TokenStorage {
  async getAccessToken(): Promise<string | null> {
    // Implementation must return correct type
    return localStorage.getItem('access_token');
  }
  
  // ... other methods with type safety
}
```

## Framework Integration Types

### React Hook Types

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Custom hook with proper OpenAPI-generated types
function useProducts(categoryId?: string): {
  products: GetProductDetailContent[] | null;
  loading: boolean;
  error: ApiErrorResponse | null;
} {
  const [products, setProducts] = useState<GetProductDetailContent[] | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<ApiErrorResponse | null>(null);
  
  useEffect(() => {
    async function fetchProducts() {
      const { data, error } = await client.catalog.listProducts({
        category_id: categoryId,
        limit: 50
      });
      
      if (data) {
        setProducts(data.products);    // ✅ Type-safe assignment
      } else if (error) {
        setError(error);               // ✅ Type-safe error handling
      }
      
      setLoading(false);
    }
    
    fetchProducts();
  }, [categoryId]);
  
  return { products, loading, error };
}
```

### Component Props

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Type-safe component props using OpenAPI types
interface ProductCardProps {
  product: GetProductDetailContent;               // ✅ Generated Product type
  onAddToCart: (productId: string, variantId: string | null) => void;
}

const ProductCard: React.FC<ProductCardProps> = ({ product, onAddToCart }) => {
  return (
    <div>
      <h3>{product.name}</h3>          {/* ✅ Type-safe access */}
      <p>{product.description}</p>     {/* ✅ Known to be string */}
      
      <button onClick={() => onAddToCart(product.id, null)}>
        Add to Cart
      </button>
    </div>
  );
};
```

## Type Utilities

### Exported Utility Types

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Response types — for reading API data
import type {
  GetProductDetailContent,
  GetCartContent,
  GetOrderDetailContent,
  GetUserDetailContent,
  ApiResult,
  ListProductsQuery,
  CreateCartBody
} from '@commercengine/storefront';

// Input types — for request bodies
import type {
  CustomerAddressInput,
  FulfillmentPreferenceInput,
} from '@commercengine/storefront';

// Readable / Writable utility types — escape hatches for advanced use
import type { Readable, Writable } from '@commercengine/storefront';

// Use in your application
interface AppState {
  currentUser: GetUserDetailContent | null;
  cart: GetCartContent | null;
  products: GetProductDetailContent[];
}
```

### Readable & Writable Utility Types

The SDK re-exports `Readable` and `Writable` utility types for advanced use cases where the generated exports don't cover your needs:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type { Readable, Writable } from '@commercengine/storefront';
import type { components } from '@commercengine/storefront';

// Manually create a response type
type MyResponseType = Readable<components['schemas']['SomeSchema']>;

// Manually create a request body type
type MyRequestType = Writable<components['schemas']['SomeSchema']>;
```

<Note>
  In most cases you won't need `Readable` or `Writable` directly — the generated base-name and `Input` exports cover standard usage. These are provided as escape hatches.
</Note>

### Type Guards

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Type guards for runtime type checking
function isProductResult(
  result: ApiResult<any>
): result is { data: { product: GetProductDetailContent }; error: null } {
  return result.data &&
         result.data.product &&
         typeof result.data.product.id === 'string';
}

// Usage with type safety
const result = await client.catalog.getProductDetail({ product_id_or_slug: 'product-id' });
if (isProductResult(result)) {
  // TypeScript knows result.data.product is GetProductDetailContent
  console.log(result.data.product.name);
}
```

## Development Experience

### IDE Integration

The SDK works seamlessly with popular IDEs:

* **VSCode**: Full IntelliSense, error squiggles, auto-imports
* **WebStorm**: Complete type information, refactoring support
* **Vim/Neovim**: TypeScript LSP provides full type information

### Compile-Time Validation

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// These errors are caught at compile time, not runtime:

// ❌ Compile error: invalid property in request body
await client.cart.createCart({
  items: [{ 
    product_id: 'id', 
    variant_id: null, 
    qty: 2  // Should be 'quantity'
  }]
});

// ❌ Compile error: wrong parameter name
const result = await client.catalog.listProducts({
  limite: 20  // Should be 'limit'
});

// ❌ Compile error: accessing wrong property
if (result.data) {
  console.log(result.data.invalidProperty); // Property doesn't exist
}
```

## Type Safety vs Direct API

<Tabs>
  <Tab title="With SDK (Type-Safe)">
    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    // Full type safety and IntelliSense with OpenAPI-generated types
    const result = await client.catalog.getProductDetail({ product_id_or_slug: 'product-id' });

    if (result.data) {
      // ✅ TypeScript knows exact structure from OpenAPI schema
      const product = result.data.product;
      console.log(product.name);         // ✅ Known to be string
      console.log(product.id);           // ✅ Known to be string
      console.log(product.is_active);    // ✅ Known to be boolean
    } else if (result.error) {
      // ✅ Typed error handling
      console.error(result.error.message); // ✅ Known error structure
    }
    ```
  </Tab>

  <Tab title="Direct API (No Types)">
    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    // No type safety - all runtime errors
    const response = await fetch('/catalog/products/product-id');
    const data = await response.json();

    if (response.ok) {
      // ❌ No type information - could fail at runtime
      console.log(data.content.name);     // Could be undefined
      console.log(data.content.price);    // Property name might be wrong
      console.log(data.content.active);   // Could be different property name
    } else {
      // ❌ Unknown error structure
      console.error(data.message);        // Could be different property name
    }
    ```
  </Tab>
</Tabs>

## Best Practices

<AccordionGroup>
  <Accordion title="Enable Strict TypeScript">
    Configure TypeScript for maximum type safety:

    ```json tsconfig.json theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "compilerOptions": {
        "strict": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "noUncheckedIndexedAccess": true
      }
    }
    ```
  </Accordion>

  <Accordion title="Use OpenAPI-Generated Types">
    Always import and use the generated types from the SDK:

    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    // ✅ Use generated types for responses
    import type { GetProductDetailContent } from '@commercengine/storefront';

    // ✅ Use Input types for request bodies
    import type { CustomerAddressInput } from '@commercengine/storefront';

    // ❌ Avoid creating custom interfaces that duplicate API schemas
    interface CustomProduct {
      id: string;
      name: string;
      // ... this will get out of sync with API
    }
    ```
  </Accordion>

  <Accordion title="Handle API Responses Properly">
    Always check for both success and error conditions:

    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const result = await client.catalog.listProducts();

    if (result.data) {
      // Handle success case
      const products = result.data.products;
      // Process products...
    } else if (result.error) {
      // Handle error case
      console.error('API Error:', result.error.message);
    } else {
      // Handle unexpected case
      console.error('Unexpected response structure');
    }
    ```
  </Accordion>
</AccordionGroup>

## Migration Benefits

When migrating from direct API calls:

<CardGroup cols={2}>
  <Card title="Catch Errors Early" icon="bug">
    Find API usage errors during development, not production
  </Card>

  <Card title="Always Current Documentation" icon="book-open">
    Types are auto-generated from OpenAPI spec and always up-to-date
  </Card>

  <Card title="Faster Development" icon="bolt">
    IntelliSense speeds up development with accurate autocomplete
  </Card>

  <Card title="Confident Refactoring" icon="arrows-rotate">
    Change APIs with confidence using IDE refactoring tools
  </Card>
</CardGroup>

<Note>
  All SDK types are automatically generated from the OpenAPI specification, ensuring they're always accurate and up-to-date with the actual API. Response types use the base schema name (e.g. `CustomerAddress`), while request body types use the `Input` suffix (e.g. `CustomerAddressInput`). The `Readable` and `Writable` utility types are also available for advanced use cases.
</Note>
