交叉类型与联合类型
交叉类型
定义:交叉类型就是取多个类型的并集,表示这个类型同时具备这几个连接起来的类型的特点;
用法:使用 & 符号定义,被&符链接的多个类型构成一个交叉类型,来看例子:
const merge = <T, U>(arg1: T, arg2: U): T & U => {
let res = <T & U>{}; // 这里指定返回值的类型兼备T和U两个类型变量代表的类型的特点
res = Object.assign(arg1, arg2); // 这里使用Object.assign方法,返回一个合并后的对象;
// 关于该方法,请在例子下面补充中学习
return res;
};
const info1 = {
name: "imooc"
};
const info2 = {
age: 18
};
const lisonInfo = merge(info1, info2);
console.log(lisonInfo.address); // error 类型“{ name: string; } & { age: number; }”上不存在属性“address”
typescript
补充阅读:
Object.assign方法可以合并多个对象,将多个对象的属性添加到一个对象中并返回;如果属性值是对象或者数组这种保存的是内存引用的引用类型,会保持这个引用,也就是如果在
Object.assign返回的的对象中修改某个对象属性值,原来用来合并的对象也会受到影响。
可以看到,传入的两个参数分别是带有属性 name 和 age 的两个对象,所以它俩的交叉类型要求返回的对象既有 name 属性又有 age 属性。
联合类型
定义:联合类型实际是几个类型的结合,但是和交叉类型不同,联合类型是要求只要符合联合类型中任意一种类型即可。
用法:它使用 | 符号定义;
应用场景:当我们的程序具有多样性,元素类型不唯一时,即使用联合类型。
const getLength = (content: string | number): number => {
if (typeof content === "string") return content.length;
else return content.toString().length;
};
console.log(getLength("abc")); // 3
console.log(getLength(123)); // 3
typescript
这里我们指定参数既可以是字符串类型也可以是数值类型,这个getLength函数的定义中,其实还涉及到一个知识点,就是类型保护,就是typeof content === “string”,后面会扩展介绍。
类型保护与类型收窄
typeof 类型保护
function processValue(value: string | number) {
if (typeof value === 'string') {
// 这里 value 被收窄为 string
return value.toUpperCase();
} else {
// 这里 value 被收窄为 number
return value.toFixed(2);
}
}
typescript
instanceof 类型保护
class Dog {
bark() {
console.log('汪汪!');
}
}
class Cat {
meow() {
console.log('喵喵!');
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
typescript
自定义类型保护
interface Fish {
swim: () => void;
}
interface Bird {
fly: () => void;
}
// 自定义类型保护函数
function isFish(pet: Fish | Bird): pet is Fish {
return 'swim' in pet;
}
function move(pet: Fish | Bird) {
if (isFish(pet)) {
pet.swim();
} else {
pet.fly();
}
}
typescript
实战:联合类型与交叉类型的组合使用
// 基础类型定义
interface Person {
name: string;
age: number;
}
interface Employee {
employeeId: string;
department: string;
}
interface Contact {
email: string;
phone: string;
}
// 联合类型:可以是多种类型之一
type PersonType = Person | Employee | Contact;
// 交叉类型:同时具备多个类型的特性
type EmployeeContact = Employee & Contact;
type PersonEmployee = Person & Employee;
// 使用联合类型
function describePerson(person: PersonType) {
if ('employeeId' in person) {
console.log(`Employee ID: ${person.employeeId}`);
}
if ('name' in person) {
console.log(`Name: ${person.name}`);
}
if ('email' in person) {
console.log(`Email: ${person.email}`);
}
}
// 使用交叉类型
const employee: EmployeeContact = {
employeeId: 'E001',
department: 'Engineering',
email: 'john@example.com',
phone: '123-456-7890',
};
typescript
TypeScript 5.x+ 增强
联合类型的改进
TypeScript 5.0+ 改进了联合类型的类型推断:
// TypeScript 5.0 之前:可能推断为 string[]
const colors = ['red', 'green', 'blue'] as const;
// TypeScript 5.0+:推断为 readonly ['red', 'green', 'blue']
type Color = typeof colors[number]; // 'red' | 'green' | 'blue'
typescript
交叉类型与 never
// 不相交类型的交叉结果为 never
type NeverType = string & number; // never
// 实际应用:检查类型是否兼容
type CheckCompatible<T, U> = T & U extends never ? false : true;
type Result1 = CheckCompatible<string, number>; // false
type Result2 = CheckCompatible<string, 'hello'>; // true
typescript
AI 辅助学习(2026 实战)
AI 工具推荐
当遇到复杂类型问题时,可以使用国内 AI 工具辅助:
| 工具 | 使用场景 | 示例提示词 |
|---|---|---|
| 豆包 | 类型错误诊断 | “为什么这个联合类型的类型保护不生效?” |
| 通义千问 | 类型收窄分析 | “如何优化这段联合类型代码的类型推断?” |
| 智谱清言 | 最佳实践 | “联合类型和交叉类型应该如何选择?” |
| 腾讯元宝 | 重构建议 | “如何用类型守卫简化这段代码?” |
实战案例
案例:理解类型保护的必要性
// 问题代码
function processValue(value: string | number) {
// Error: 类型 'string' 上不存在 'toFixed' 方法
return value.toFixed(2);
}
typescript
AI 辅助解决:
- 向 AI 描述问题
- AI 会建议使用类型保护
- 提供优化方案:
function processValue(value: string | number) { if (typeof value === 'number') { return value.toFixed(2); } return value.length.toString(); }typescript
总结
关键要点
- 交叉类型 (
&):同时具备多个类型的特性 - 联合类型 (
|):满足其中任意一种类型即可 - 类型保护:确保在运行时安全地操作联合类型
- 类型收窄:通过条件判断让 TypeScript 更精确地推断类型
最佳实践
- ✅ 合理使用联合类型:提高代码的灵活性
- ✅ 类型保护优先:使用
typeof、instanceof、in等操作符 - ✅ 自定义类型保护:对于复杂场景,定义
is类型谓词 - ✅ 善用 AI 工具:遇到复杂类型问题时,让 AI 帮你分析和解决
记住:类型保护是使用联合类型的关键!
↑