一、交叉类型与联合类型的本质区别
在TypeScript中,交叉类型(Intersection Types)和联合类型(Union Types)是两种常见的类型组合方式,但它们的行为截然不同。
交叉类型使用 & 符号,将多个类型合并为一个新类型,新类型会包含所有成员。例如:
// 技术栈:TypeScript
interface Person {
name: string;
age: number;
}
interface Employee {
company: string;
role: string;
}
// 交叉类型:同时具备Person和Employee的所有属性
type EmployeePerson = Person & Employee;
const john: EmployeePerson = {
name: "John",
age: 30,
company: "TechCorp",
role: "Developer"
};
// 注释:john必须包含name、age、company、role四个属性
联合类型使用 | 符号,表示一个值可以是几种类型之一。例如:
type StringOrNumber = string | number;
function printId(id: StringOrNumber) {
console.log(id);
}
printId(101); // 合法
printId("ABC101"); // 合法
// printId(true); // 报错:boolean不在联合类型中
关键区别:
- 交叉类型是“合并”,要求同时满足所有类型约束。
- 联合类型是“或”,只需满足其中任意一种类型约束。
二、类型断言的安全边界
类型断言(Type Assertion)允许开发者手动指定值的类型,但滥用会导致运行时错误。TypeScript提供了两种语法:
const userInput: unknown = "Hello World";
// 语法1:尖括号(不推荐在JSX中使用)
const str1 = <string>userInput;
// 语法2:as关键字(推荐)
const str2 = userInput as string;
安全边界问题:
interface Cat {
meow(): void;
}
interface Dog {
bark(): void;
}
function isCat(animal: Cat | Dog): animal is Cat {
return "meow" in animal;
}
const pet: Cat | Dog = { bark: () => console.log("Woof!") };
if (isCat(pet)) {
pet.meow(); // 类型收窄为Cat
} else {
pet.bark(); // 类型收窄为Dog
}
// 注释:通过类型守卫(Type Guard)避免不安全断言
最佳实践:
- 优先使用类型守卫(如
typeof、instanceof、自定义函数)。 - 避免对
any或unknown直接断言,除非明确知道运行时类型。
三、映射类型的灵活应用
映射类型(Mapped Types)允许基于旧类型创建新类型,常见于工具类型(Utility Types)如 Partial、Readonly。
基础示例:
type Keys = "name" | "age";
type Person = {
[K in Keys]: string;
};
// 等价于 { name: string; age: string; }
进阶应用:
interface User {
id: number;
name: string;
password: string;
}
// 剔除password字段,生成新类型
type SafeUser = Omit<User, "password">;
// 等价于 { id: number; name: string; }
// 将所有字段改为可选
type PartialUser = Partial<User>;
// 等价于 { id?: number; name?: string; password?: string; }
关联技术:结合 keyof 实现动态映射:
type Nullable<T> = {
[P in keyof T]: T[P] | null;
};
const nullableUser: Nullable<User> = {
id: null,
name: null,
password: "123456" // 仍允许非null
};
四、应用场景与注意事项
交叉类型:适合合并多个接口或扩展第三方库类型。
type ReactProps = Props & State; // 合并React组件props和state联合类型:适合处理异构数据(如API响应)。
type APIResponse = SuccessResponse | ErrorResponse;类型断言:谨慎用于DOM操作或遗留代码迁移。
const input = document.getElementById("user") as HTMLInputElement;映射类型:适合批量修改属性(如生成表单验证规则)。
注意事项:
- 避免深度嵌套的交叉类型,可能导致类型推断性能下降。
- 联合类型需用类型守卫收窄范围,否则只能访问共有成员。
总结
交叉类型与联合类型分别解决“合并”和“选择”问题,类型断言需在安全边界内使用,而映射类型能大幅提升类型复用性。掌握这些特性后,可以更灵活地设计复杂类型系统。
评论