# TypeScript Branded Types

TypeScript uses a **structural type system**. This means if two objects have the same shape, they are considered compatible. However, sometimes you want to distinguish between two types that have the same underlying structure (e.g., a `UserId` string and an `Email` string) to prevent logic errors.

**Branded Types** (also called Opaque Types or Nominal Typing) allow you to create types that are distinct from their underlying primitives.

## 1. The Problem: Structural Typing

```typescript
type UserId = string;
type PostId = string;

function deletePost(postId: PostId) { /* ... */ }

const myUserId: UserId = "user_123";
const myPostId: PostId = "post_456";

// DANGER: TypeScript allows this because both are just 'string'
deletePost(myUserId); 
```

## 2. Creating a Branded Type

To fix this, we intersect the primitive type with an object containing a unique "brand" property. This property doesn't actually exist at runtime, but it tricks the compiler.

```typescript
// Define the Brand
type Brand<K, T> = K & { __brand: T };

// Define Branded Types
type UserId = Brand<string, "UserId">;
type PostId = Brand<string, "PostId">;

// Usage
function deletePost(postId: PostId) {
    console.log("Deleting post", postId);
}

const myUserId = "user_123" as UserId;
const myPostId = "post_456" as PostId;

deletePost(myPostId); // OK

// Error: Argument of type 'UserId' is not assignable to parameter of type 'PostId'.
// deletePost(myUserId); 
```

## 3. Validation Functions (Type Guards)

You shouldn't just cast (`as`) blindly. Branded types are perfect for ensuring data has passed a validation check.

```typescript
type Email = string & { __brand: "Email" };

function isEmail(input: string): input is Email {
    return input.includes("@");
}

function sendWelcomeEmail(email: Email) {
    console.log("Sending to", email);
}

const input = "not-an-email";

if (isEmail(input)) {
    // TypeScript knows 'input' is 'Email' here
    sendWelcomeEmail(input);
} else {
    // sendWelcomeEmail(input); // Error
}
```

## 4. Runtime Impact

Branded types are a **compile-time only** construct. The `__brand` property is never added to the object at runtime. The compiled JavaScript just sees plain strings or numbers. This means there is zero runtime overhead.

[[programming/javascript/typescript/typescript]]
[[programming/javascript/typescript/intersection-types]]