TypeScript 如何做类型排除
在写代码时,你有没有过这种经历:明明已经定义了一个包含多种类型的变量,想单独取出其中某几类,却不小心混入了不需要的类型,导致后续逻辑出错?比如你要做一个电商系统的商品筛选,商品类型有“实物”“虚拟”“服务”三种,你只想显示“实物”,结果不小心把“虚拟”的优惠券也显示出来了。在 TypeScript 里,这种“从现有类型里剔除不需要的部分”的操作,就叫类型排除。
先搞懂基础:什么是类型排除?
简单说,类型排除就是“从一个大的类型集合里,去掉你不想要的那些类型,留下需要的部分”。就像你整理衣柜时,把冬天的厚外套挑出来,把夏天的短袖、裙子都放到一边,最后只留下你要的厚外套。

举个生活化的例子:假设我们有一个“水果”类型,包含苹果、香蕉、橙子、草莓四种具体类型。如果我们想排除草莓,只留下苹果、香蕉、橙子,这就是一次简单的类型排除。在 TypeScript 里,这个操作有专门的语法实现,不用自己手动写一堆判断条件。
第一种常用方法:用 `Exclude` 工具类型
TypeScript 自带了很多工具类型,Exclude 就是专门用来做“排除”的。它的用法很简单:Exclude<要处理的大类型, 要排除的类型>。
还是拿水果举例:
`typescript
// 定义包含四种水果的大类型
type Fruit = 'apple' | 'banana' | 'orange' | 'strawberry';
// 用 Exclude 排除草莓,留下其他三种
type NoStrawberry = Exclude<Fruit, 'strawberry'>;
`
这时候你打印 NoStrawberry,它就会变成 'apple' | 'banana' | 'orange',正好是我们想要的结果。
再换个更贴近代码的例子:假设我们定义了一个“用户角色”类型,包含普通用户、管理员、访客、商家四种,现在要排除“访客”这个角色,只处理实际有操作权限的用户,就可以这么写:
`typescript
type UserRole = 'normal' | 'admin' | 'guest' | 'merchant';
type OperableRole = Exclude<UserRole, 'guest'>;
// 现在 OperableRole 就是 'normal' | 'admin' | 'merchant'
`
是不是很简单?就像你从一堆卡片里,把标着“guest”的卡片抽走,剩下的就是可用的。
第二种场景:排除对象类型里的属性
刚才的例子都是简单的字符串类型,那如果是对象类型,想排除某个属性怎么办?比如我们有一个“商品信息”对象,包含商品名、价格、库存、销量四个属性,现在要把“销量”这个属性去掉,只保留商品的核心信息。这时候可以用 Omit 工具类型。
用法也很直观:Omit<要处理的对象类型, 要排除的属性名>。举个例子:
`typescript
// 定义商品对象类型
type Product = {
name: string;
price: number;
stock: number;
sales: number;
};
// 排除 sales 属性,得到新的对象类型
type BasicProduct = Omit<Product, 'sales'>;
`
这时候 BasicProduct 就变成了只包含 name、price、stock 的类型,完全去掉了销量属性。就像你给商品做信息卡,把“销量”这一栏划掉,只留下需要填的内容。
注意别踩的小坑
用类型排除的时候,有个小细节要注意:不管是 Exclude 还是 Omit,排除的内容必须是“原类型里真实存在”的,不然 TypeScript 会报错。比如你刚才的 Fruit 类型里没有“mango”,要是写 Exclude<Fruit, 'mango'>,TypeScript 就会提示你“类型 'mango' 不存在于 'Fruit' 中”,相当于你想从衣柜里拿一件不存在的衣服,自然会出错。
另外,如果你要排除多个类型,比如既想排除“strawberry”又想排除“banana”,也很简单,直接在第二个参数里用竖线分隔就行:
`typescript
type NoBerryAndBanana = Exclude<Fruit, 'strawberry' | 'banana'>;
// 结果就是 'apple' | 'orange'
`
掌握了这些方法,你在写代码的时候,就能更精准地控制类型范围,避免因为不小心混入不需要的类型而出错,就像整理衣柜时再也不会把不需要的衣服混在里面一样。