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

# Type Safety

> Compile-time validation and type-checked flag values

## The Type Safety Problem

Traditional feature flag systems use string literals and untyped values:

```typescript theme={null}
// ❌ Problems with traditional approach
const isEnabled = flags.get("new_checkout"); // Typo in flag name
const theme = flags.get("theme"); // What type is this?
const maxItems = flags.get("maxItems"); // Could be undefined

// Runtime errors waiting to happen!
if (theme.toUpperCase() === "DARK") {
  // TypeError if theme is undefined
  // ...
}
```

## FlagKit's Type-Safe Approach

FlagKit generates TypeScript types from your flag definitions:

```typescript theme={null}
// ✅ FlagKit with full type safety
import { flags } from "./.flagkit/generated/client";

// Autocomplete knows all available flags
const isEnabled = flags.get("newCheckout"); // boolean
//                          ^ Autocomplete suggests: newCheckout, theme, maxItems

// Type is enforced
const theme = flags.get("theme"); // 'light' | 'dark' | 'auto'

// Compiler catches typos
const broken = flags.get("them"); // ❌ Compile error: 'them' doesn't exist
```

## Generated Types

Running `flagkit generate` creates comprehensive TypeScript types:

<CodeGroup>
  ```typescript Flag Names theme={null}
  // All flag names as union type
  export type FlagName = 
    | 'newCheckout'
    | 'theme'
    | 'maxItems'
    | 'apiEndpoint';
  ```

  ```typescript Flag Values theme={null}
  // Map of flag names to their value types
  export type FlagValues = {
    newCheckout: boolean;
    theme: "light" | "dark" | "auto";
    maxItems: number;
    apiEndpoint: string;
  };
  ```

  ```typescript Context Type theme={null}
  // User context with type hints
  export type FlagContext = {
    userId?: string;
    rolloutPercent?: number;
    email?: string;
    plan?: "free" | "pro" | "enterprise";
    environment?: "development" | "staging" | "production";
    [key: string]: any; // Allow custom properties
  };
  ```
</CodeGroup>

## Type-Checked API

The `flags.get()` method is fully type-checked:

```typescript theme={null}
// Generic signature
function get<K extends FlagName>(name: K, context?: FlagContext): FlagValues[K];

// Usage examples
const a: boolean = flags.get("newCheckout"); // ✅ Correct type
const b: string = flags.get("newCheckout"); // ❌ Type error!

const c: "light" | "dark" | "auto" = flags.get("theme"); // ✅
const d: string = flags.get("theme"); // ❌ Type error - too broad!

// Type inference works
const theme = flags.get("theme");
if (theme === "dark") {
  // ✅ TypeScript knows theme is the enum
  applyDarkMode();
}
```

## Compile-Time Validation

FlagKit catches errors at compile time, not runtime:

### 1. Typos in Flag Names

```typescript theme={null}
// ❌ Compile error
const value = flags.get("newChckout");
//                      ~~~~~~~~~~~~
// Error: Argument of type '"newChckout"' is not assignable
// to parameter of type 'FlagName'
```

### 2. Invalid Default Values

```typescript flags.config.ts theme={null}
// ❌ Compile error
export const flags = defineFlags({
  theme: flag.enum(["light", "dark"]).default("auto"), // 'auto' not in enum!
  //       ~~~~~~
  // Error: Argument of type '"auto"' is not assignable to
  // parameter of type '"light" | "dark"'
});
```

### 3. Type Mismatches

```typescript theme={null}
// ❌ Compile error
const maxItems: string = flags.get("maxItems");
//    ~~~~~~~~
// Error: Type 'number' is not assignable to type 'string'
```

## Refactoring Safety

Rename flags confidently using TypeScript's refactoring tools:

```typescript theme={null}
// Before: Flag named 'newCheckout'
const isEnabled = flags.get("newCheckout");

// After: Rename to 'newCheckoutFlow'
// 1. Rename in flags.config.ts
// 2. Run `flagkit generate`
// 3. TypeScript shows all places that need updating

const isEnabled = flags.get("newCheckout");
//                          ~~~~~~~~~~~~
// Error: Argument of type '"newCheckout"' is not assignable...
```

<Tip>
  Use your IDE's "Find All References" feature to locate all usages of a flag
  before renaming.
</Tip>

## Type-Safe Context

Context values are also type-checked:

```typescript theme={null}
// Define custom context type
export type AppContext = {
  userId: string; // Required
  plan: "free" | "pro";
  betaTester?: boolean;
};

// Use with flags
const isEnabled = flags.get("newCheckout", {
  userId: user.id,
  plan: user.plan,
  betaTester: user.isBeta,
  // unknownKey: 'value'  // ❌ Error if context is strictly typed
});
```

## Enum Flags

Enum flags get full type safety:

```typescript flags.config.ts theme={null}
export const flags = defineFlags({
  theme: flag.enum(["light", "dark", "auto"]).default("auto"),
});
```

```typescript theme={null}
// Usage is type-safe
const theme = flags.get("theme");

// TypeScript knows exact values
if (theme === "light") {
  // ✅
  setLightMode();
} else if (theme === "dark") {
  // ✅
  setDarkMode();
} else {
  setAutoMode(); // theme is 'auto'
}

// Invalid values caught
if (theme === "blue") {
  // ❌ Compile error
  //          ~~~~~~
  // Error: This condition will always return 'false'
}
```

## Number Flags with Constraints

Number flags can have min/max constraints:

```typescript flags.config.ts theme={null}
export const flags = defineFlags({
  pageSize: flag.number().min(1).max(100).default(20),
});
```

```typescript theme={null}
// Runtime validation
const pageSize = flags.get("pageSize"); // number (1-100)

// TypeScript can't enforce numeric ranges, but runtime will
// If someone edits decision-tree.json to set pageSize: 200,
// FlagKit will clamp to 100
```

<Note>
  TypeScript can enforce type (string, number, boolean) but not value ranges.
  Runtime validation ensures values stay within constraints.
</Note>

## Pattern-Based String Flags

String flags can use regex patterns for validation:

```typescript flags.config.ts theme={null}
export const flags = defineFlags({
  apiEndpoint: flag
    .string()
    .pattern(/^https:\/\//)
    .default("https://api.example.com"),

  emailDomain: flag
    .string()
    .pattern(/^[\w-]+(\.[\w-]+)*\.\w+$/)
    .default("example.com"),
});
```

## Benefits Summary

<CardGroup cols={2}>
  <Card title="Catch Errors Early" icon="bug">
    Compile-time validation prevents runtime failures
  </Card>

  <Card title="IDE Support" icon="sparkles">
    Autocomplete, go-to-definition, and refactoring tools
  </Card>

  <Card title="Self-Documenting" icon="book">
    Types serve as inline documentation
  </Card>

  <Card title="Refactor Safely" icon="shield">
    Rename flags without breaking code
  </Card>
</CardGroup>

## Next Steps

<Card title="Deterministic Rollouts" icon="chart-line" href="/core-concepts/deterministic-rollouts">
  Learn about type-safe percentage-based rollouts
</Card>
