Z
ZHANK
编程在线教程TypeScript 教程品牌类型与标称类型
类型编程

品牌类型与标称类型

品牌类型模拟标称类型、Flavor 类型、防止 ID 混淆

品牌类型与标称类型

TypeScript 是结构类型系统——两个形状相同的类型被视为"相同"。品牌类型(Branded Types)模拟标称类型,防止 ID 混淆。

学完本章你将: 掌握品牌类型、Flavor 类型、防止 ID 混淆。


问题:结构类型带来的混淆

typescript
type UserId = number;
type OrderId = number;

function getUser(id: UserId) { }
function getOrder(id: OrderId) { }

const uid: UserId = 1;
getOrder(uid);  // ✅ 编译通过!但逻辑上 UserId 不应该传给 getOrder

解决:品牌类型

typescript
// 给类型打上"品牌"标记(编译时存在,运行时消失)
type Brand<T, B> = T & { __brand: B };

type UserId = Brand<number, "UserId">;
type OrderId = Brand<number, "OrderId">;

function getUser(id: UserId) { }
function getOrder(id: OrderId) { }

const uid = 1 as UserId;
// getOrder(uid);  // ❌ 类型错误!完美

工厂函数创建品牌类型

typescript
function createUserId(id: number): UserId {
    return id as UserId;  // 唯一的"不安全"转换点
}

// 使用——无法意外混淆
const uid = createUserId(42);
getUser(uid);  // ✅
// getOrder(uid);  // ❌

Flavor 类型(轻量版)

typescript
// Flavor 不强制类型转换,只是一个"提示"
type Flavor<T, F> = T & { __flavor?: F };

type Email = Flavor<string, "Email">;
type Username = Flavor<string, "Username">;

// 可以互相赋值(因为是 string),但 IDE 会提示