You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript新Extract/Exclude条件类型的实用场景问询

Exclude & Extract 实用场景分享

嘿,我完全懂你为啥一开始会觉得Exclude和Extract有点“摸不着头脑”——毕竟Pick、Omit这些直接操作对象属性的内置类型太常用了,而这俩看起来只跟联合类型挂钩,好像离日常开发有点远。但其实它们在处理联合类型的细化、过滤时特别实用,给你举几个肯定能用上的场景:

1. 状态管理:筛选特定状态类型

在React、Vue的状态管理(比如useReducer、Pinia)里,我们经常会定义包含多种状态的联合类型,这时候Extract/Exclude能快速帮我们筛选出需要的状态:

// 定义API请求的三种状态
type SuccessResponse = { type: 'success'; data: User[] };
type ErrorResponse = { type: 'error'; message: string };
type LoadingState = { type: 'loading' };
type RequestState = SuccessResponse | ErrorResponse | LoadingState;

// 提取仅成功状态的类型
type OnlySuccess = Extract<RequestState, { type: 'success' }>;
// 结果:{ type: 'success'; data: User[] }

// 排除加载状态,只保留结果/错误状态
type NonLoadingStates = Exclude<RequestState, LoadingState>;
// 结果:SuccessResponse | ErrorResponse

当你需要写只处理成功状态的逻辑时,用OnlySuccess就能精准约束类型,避免处理其他状态的冗余代码。

2. 路由系统:筛选特定格式的路由

如果你的项目用了字符串联合类型定义路由,结合模板字面量类型,Extract/Exclude能快速筛选出符合规则的路由:

type AllRoutes = '/home' | '/user/profile' | '/user/settings' | '/admin/dashboard' | '/admin/users';

// 提取所有/user开头的用户路由
type UserRoutes = Extract<AllRoutes, `/user/${string}`>;
// 结果:'/user/profile' | '/user/settings'

// 排除/admin相关的后台路由,得到前端公共路由
type PublicRoutes = Exclude<AllRoutes, `/admin/${string}`>;
// 结果:'/home' | '/user/profile' | '/user/settings'

这个场景在写路由守卫、生成菜单列表时特别好用,不用手动枚举符合条件的路由。

3. 类型细化:移除可选类型中的undefined

当你有一个包含undefined的联合类型(比如可选参数、可选属性的类型),Exclude可以快速帮你得到必填的类型:

// 工具类型:移除联合类型中的undefined
type RequiredValue<T> = Exclude<T, undefined>;

// 可选的用户名类型
type MaybeUsername = string | undefined;
// 得到必填的用户名类型
type Username = RequiredValue<MaybeUsername>; // string

// 另一个例子:提取仅鼠标事件类型
type AllEvents = MouseEvent | KeyboardEvent | TouchEvent;
type MouseOnlyEvents = Extract<AllEvents, { clientX: number }>;
// 结果:MouseEvent(只有它包含clientX属性)

在处理事件回调、表单参数时,这种类型细化能让你的类型约束更精准。

4. 结合其他工具类型:处理对象联合的属性筛选

把Extract和Pick、Omit结合,能解决更复杂的对象联合类型处理问题:

type Product = 
  | { type: 'book'; title: string; pages: number }
  | { type: 'movie'; title: string; duration: number }
  | { type: 'music'; title: string; artist: string };

// 先提取所有带pages属性的产品(也就是书籍),再筛选title和pages属性
type BookInfo = Pick<Extract<Product, { pages: number }>, 'title' | 'pages'>;
// 结果:{ title: string; pages: number }

// 排除音乐类型,得到书籍和电影的联合类型
type NonMusicProducts = Exclude<Product, { type: 'music' }>;
// 结果:{ type: 'book'; ... } | { type: 'movie'; ... }

单独用Pick只能处理单一对象类型,而Extract先帮我们从联合里筛选出目标对象,再结合Pick就能精准提取需要的属性。

总的来说,Exclude和Extract的核心是对联合类型做“筛选”和“剔除”,日常开发里联合类型的使用场景比你想象的多——状态管理、路由、API响应、事件处理这些地方都能用上,把它们和其他类型工具结合,能解决很多复杂的类型细化问题。

内容的提问来源于stack exchange,提问作者Aston Richworth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:59:04