# TypeScript Patterns

This document outlines TypeScript type definitions, patterns, and conventions for componentLibrary.

> **Note:** For prop naming conventions, see [Prop Naming Patterns](./prop-naming-patterns.md)

## Type Definitions Structure

All components maintain a separate `types.ts` file with:

### Component Props Type
```typescript
export type ComponentProps = {
  // Component-specific props
  specificProp: string;

  // Standard props
  className?: string;
  style?: React.CSSProperties;
  children?: React.ReactNode; // optional - may not make sense everywhere

  // Variant if applicable
  variant?: 'primary' | 'secondary' | 'tertiary';
};
```

### Field Props Types
```typescript
export type ContentFieldsProps = {
  // Field configuration props with descriptive names
  fieldNameLabel?: string;
  fieldNameName?: string;
  fieldNameDefault?: FieldType;
};

export type StyleFieldsProps = {
  // Style-related field configurations
  styleFieldLabel?: string;
  styleFieldName?: string;
  styleFieldDefault?: StyleType;
};
```

**Pattern:** Field props always follow `{field}Label`, `{field}Name`, `{field}Default` naming convention and property order.

## Advanced TypeScript Patterns

### Union Types for String Literals
Define union types for valid string values:

```typescript
export type DividerOrientation = 'horizontal' | 'vertical';
export type DividerAlignment = 'stretch' | 'start' | 'center' | 'end';
export type DividerBorderStyle = 'solid' | 'dotted' | 'dashed' | 'double';
export type HeadingLevel = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
```

### Discriminated Union Pattern
For components that render different HTML elements based on props (like Button):

```typescript
// Base props shared across all variants
export type BaseButtonProps = {
  variant?: 'primary' | 'secondary' | 'tertiary';
  className?: string;
  style?: React.CSSProperties;
  // ... shared props
};

// Variant 1: Renders as <button>
export type ButtonAsButtonProps = BaseButtonProps & {
  buttonType: 'button';  // Discriminator
  onClick?: () => void;
  disabled?: boolean;
};

// Variant 2: Renders as <a>
export type ButtonAsLinkProps = BaseButtonProps & {
  buttonType: 'link';  // Discriminator
  href?: string;
  target?: '_self' | '_blank' | '_parent' | '_top';
};

// Union type - TypeScript will discriminate based on buttonType
export type ButtonProps = ButtonAsButtonProps | ButtonAsLinkProps;
```

**Usage in component:**
```typescript
const ButtonComponent = ({
  buttonType,
  ...rest
}: ButtonProps) => {
  // TypeScript knows which props are available based on buttonType
  if (buttonType === 'button') return renderButton(rest);
  return renderLink(rest);
};
```

### Template Literal Types
Strongly type strings whenever possible. For example, for typed pixel values:

```typescript
type PixelValue = `${number}px`;

export type DividerProps = {
  spacing?: PixelValue;  // Only accepts strings like "16px"
};
```

### Conditional Field Props Types
Icon component shows pattern for optional vs required toggle props:

```typescript
type IconToggleProps = {
  showIconLabel?: string;
  showIconName?: string;
  showIconDefault?: typeof BooleanFieldDefaults;
  addIconToggle: true;  // Required when using toggle
};

type IconContentFieldsWithoutToggleProps = {
  iconLabel?: string;
  iconName?: string;
  iconDefault?: typeof IconFieldDefaults;
  addIconToggle?: boolean;  // Optional
};

// Union allows either with toggle or without
export type ContentFieldsProps =
  | IconContentFieldsWithToggleProps
  | IconContentFieldsWithoutToggleProps;
```

**Pattern:** Use `typeof XXXXFieldDefaults` wherever possible on default field properties.

## Complete Types Example

```typescript
// types.ts
export type ComponentProps = {
  variant?: 'primary' | 'secondary' | 'tertiary';
  className?: string;
  style?: React.CSSProperties;
  children?: React.ReactNode;
};

export type ContentFieldsProps = {
  fieldLabel?: string;
  fieldName?: string;
  fieldDefault?: string;
};

export type StyleFieldsProps = {
  styleFieldLabel?: string;
  styleFieldName?: string;
  styleFieldDefault?: string;
};
```
