使用管道符 |
表示多选一关系,典型场景:处理可能存在多种类型的变量
// 基础示例:处理数值型ID(number)或哈希型ID(string)
type EntityID = number | string;
function getEntity(id: EntityID) {
// 类型守卫处理分支逻辑
if (typeof id === 'number') {
console.log(`Fetching by numeric ID: ${id.toFixed(2)}`);
} else {
console.log(`Fetching by hash ID: ${id.toUpperCase()}`);
}
}
通过公共字段实现精确类型推断,适用于状态机等场景
// 图形系统形状定义
type Shape =
| { kind: "circle"; radius: number } // 圆形
| { kind: "square"; size: number } // 正方形
| { kind: "rectangle"; width: number; height: number }; // 长方形
function calculateArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2; // 自动识别radius属性
case "square":
return shape.size ** 2; // 自动识别size属性
case "rectangle":
return shape.width * shape.height; // 自动识别宽高属性
}
}
与 undefined
联用实现可选参数类型定义
// 带缓存的读取函数
type CacheConfig = {
maxAge: number;
useLocalStorage?: boolean;
};
function readCache(key: string, config?: CacheConfig) {
// 类型自动推断为 CacheConfig | undefined
const effectiveConfig = config || { maxAge: 3600 };
}
any
类型更安全string | number | boolean
建议重构为更具体的联合使用 &
符号实现类型合并,类似接口继承但更灵活
// 基础示例:合并用户基础信息与权限信息
type User = {
id: number;
name: string;
};
type Permission = {
canEdit: boolean;
isAdmin: boolean;
};
type UserWithPermission = User & Permission;
const adminUser: UserWithPermission = {
id: 1,
name: "Alice",
canEdit: true,
isAdmin: true
};
实现功能组合的最佳实践
// 可序列化能力混入
type Serializable = {
serialize(): string;
};
class BaseModel {
constructor(public id: number) {}
}
// 通过交叉类型实现混入
type SerializableModel = BaseModel & Serializable;
const userModel: SerializableModel = {
...new BaseModel(1),
serialize() {
return JSON.stringify(this);
}
};
合并多个配置类型生成完整配置
// 分阶段配置定义
type BaseConfig = {
apiEndpoint: string;
timeout: number;
};
type AuthConfig = {
clientId: string;
token: string;
};
type LoggingConfig = {
logLevel: "debug" | "info";
};
// 生成完整配置类型
type AppConfig = BaseConfig & AuthConfig & LoggingConfig;
const config: AppConfig = {
apiEndpoint: "/api",
timeout: 5000,
clientId: "web-app",
token: "abc123",
logLevel: "debug"
};
never
| 特性 | 联合类型(|) | 交叉类型(&) |
|---------------------|------------------------|-----------------------|
| 语义 | 逻辑"或"关系 | 逻辑"与"关系 |
| 适用场景 | 处理不同类型输入 | 合并类型特性 |
| 基础类型操作 | string | number 有效 | string & number => never |
| 对象类型合并 | 创建包含共有属性的类型 | 合并所有属性 |
// 危险操作:未进行类型检查直接访问属性
function getLength(input: string | string[]) {
// 编译错误:未收缩类型时访问length不安全
return input.length; // Error: Property 'length' does not exist on type 'string | string[]'
// 正确做法:类型断言或类型守卫
if (typeof input === 'string') return input.length;
return input.length;
}
// 危险操作:基本类型交叉产生 never
type Impossible = string & number; // 类型为 never
// 实际影响
function handleValue(val: string & number) {
console.log(val); // 该函数永远无法被调用
}
// 自定义类型守卫
function isErrorResponse(
response: SuccessResponse | ErrorResponse
): response is ErrorResponse {
return (response as ErrorResponse).error !== undefined;
}
// 使用示例
if (isErrorResponse(res)) {
console.error(res.error.message);
}
// 条件类型中的分发特性
type ExtractString = T extends string ? T : never;
// 实际应用
type Result = ExtractString<"hello" | 42 | true>; // 得到类型 "hello"
// 建议:独立类型声明文件(types.d.ts)
export type APIResponse =
| { status: 'success'; data: T }
| { status: 'error'; code: number };
/**
* 用户身份联合类型
* @typedef {AdminUser | NormalUser} UserRole
* @property {boolean} AdminUser.isSuperAdmin - 超级管理员标识
* @property {string} NormalUser.department - 所属部门
*/
type UserRole = AdminUser | NormalUser;
// 避免过度使用交叉类型
// 不推荐:超过3层的交叉类型
type OverComplex = A & B & C & D;
// 推荐:使用接口继承重构
interface Combined extends A, B, C, D {}
联合类型与交叉类型共同构成了TS类型系统的核心武器库。
联合类型(Union Types)擅长处理不确定性输入,交叉类型(Intersection Types)专注解决确定性的类型组合。
掌握二者的本质区别与适用边界,配合类型守卫等辅助手段,能够大幅提升代码的类型安全性。
在实际项目中,建议将复杂类型操作限制在系统边界层(如API响应处理),保持核心业务逻辑的类型简洁性。