掌握 TypeScript 条件类型

可用语言 :

啊,TypeScript中的条件类型...它们就像变色龙一样,能根据代码的需求改变形态和适应!也许你已经熟悉了基本类型,但是使用条件类型,我们就能更上一层楼。想象一下,这些智能类型能够根据情况自适应,就像类型系统中的超级英雄。来吧,让我们坐下来,准备为你的TypeScript代码增添一些魔法!🧙‍♂️

为什么要使用条件类型?🧐

在TypeScript中,我们喜欢一切都井然有序,类型完备。但有时,我们的代码需要一个能够根据特定条件调整的类型。想象一下,你有一个函数,根据输入参数的不同可能返回stringnumber。😱 没有条件类型的话,我们就得手动处理每种情况,这很快就会变得繁琐!幸运的是,条件类型就像类型忍者一样,为我们带来了灵活性和响应性。🥷

基础:条件类型语法 🧩

条件类型有点像三元运算符,但是用于类型。看看这个开胃小菜:

typescript
1type IsString<T> = T extends string ? '这是字符串' : '这不是字符串';

在这个例子中,IsString是一个条件类型,用于检查T是否为string类型。如果是,返回"这是字符串",否则返回"这不是字符串"。看起来很简单,但等着看看在更高级的场景中能做什么!

实践案例:根据配置调整类型 🛠️

想象一个接收配置参数并根据该配置返回不同类型的函数。条件类型非常适合这种魔法般的转换 ✨!

代码示例

typescript
1type Config = {
2 mode: '简单' | '详细';
3};
4
5type Response<T extends Config> = T['mode'] extends '简单'
6 ? { data: string }
7 : { data: string; details: string[] };
8
9function fetchData<T extends Config>(config: T): Response<T> {
10 if (config.mode === '简单') {
11 return { data: '简化数据' } as Response<T>;
12 } else {
13 return {
14 data: '完整数据',
15 details: ['详情1', '详情2'],
16 } as Response<T>;
17 }
18}
19
20const simpleConfig = { mode: '简单' };
21const detailedConfig = { mode: '详细' };
22
23const resultSimple = fetchData(simpleConfig); // { data: "简化数据" }
24const resultDetailed = fetchData(detailedConfig); // { data: "完整数据", details: [...] }

在这个例子中,Response<T>根据mode"简单"还是"详细"来调整类型。看看这个魔法:fetchData(simpleConfig)只返回带有data的对象,而fetchData(detailedConfig)还包含details。很实用,对吧?

嵌套条件类型:自定义类型系统 🧇

为什么要止步于此?你还可以嵌套条件类型来处理更精确的场景!想象一下,你不仅要根据mode调整类型,还要考虑用户是否已认证。准备好看看类型体操了吗?🎢

typescript
1type UserResponse<
2 T extends Config,
3 Authenticated extends boolean,
4> = Authenticated extends true
5 ? T['mode'] extends '简单'
6 ? { data: string }
7 : { data: string; details: string[] }
8 : { error: '未认证' };
9
10function fetchUserData<T extends Config, Authenticated extends boolean>(
11 config: T,
12 isAuthenticated: Authenticated,
13): UserResponse<T, Authenticated> {
14 if (!isAuthenticated) {
15 return { error: '未认证' } as UserResponse<T, Authenticated>;
16 }
17 if (config.mode === '简单') {
18 return { data: '简化数据' } as UserResponse<T, Authenticated>;
19 } else {
20 return {
21 data: '完整数据',
22 details: ['详情1', '详情2'],
23 } as UserResponse<T, Authenticated>;
24 }
25}
26
27const resultAuthSimple = fetchUserData(simpleConfig, true); // { data: "简化数据" }
28const resultAuthDetailed = fetchUserData(detailedConfig, true); // { data: "完整数据", details: [...] }
29const resultNotAuth = fetchUserData(detailedConfig, false); // { error: "未认证" }

这里,UserResponse根据两个条件调整类型:modeisAuthenticated。结果如何?一个超精确的类型系统,覆盖所有可能的情况!

使用infer的高级条件类型:类型推断 🕵️‍♂️

准备好看看魔术表演了吗?TypeScript在条件类型中提供了一个特殊的关键字:infer。有了它,你可以直接在条件类型中推断类型。这在提取复杂类型信息时特别有用!

使用infer的示例

typescript
1type ReturnTypeOfFunction<T> = T extends (...args: any[]) => infer R
2 ? R
3 : never;
4
5function getHello(): string {
6 return '你好,世界!';
7}
8
9type HelloReturnType = ReturnTypeOfFunction<typeof getHello>; // 结果:string

这里,ReturnTypeOfFunction使用infer R来推断函数的返回类型。在这个例子中,HelloReturnType的类型是string,因为getHello返回一个字符串。

总结 🎉

TypeScript中的条件类型就像是给你的代码赋予了超能力。它们让你能够创建动态类型,保持严格的类型检查,同时让代码更加简洁。那么,准备好让你的同事大开眼界了吗?开始尝试这些条件类型,探索构建TypeScript代码的新方式吧!🚀

不再有模糊的类型作为借口:有了条件类型,你的TypeScript代码将变得无懈可击!👌

分享这篇文章


Sébastien Timoner

Sébastien TIMONER

首席开发工程师
定制开发专家
Aix-en-Provence, France

作为 Web 开发和技术团队管理专家,我专注于创建和优化高性能数字解决方案。通过对 React.js、Node.js、TypeScript、Symfony 和 IoT 领域的 Zephyr OS 等现代技术的深入掌握,我确保在 offroadLabs 中为各行业企业的复杂 SaaS 和 IoT 项目从设计到生产的成功。

offroadLabs,我提供定制开发服务,结合技术专长和协作方法。无论是创建创新的 SaaS 解决方案、使用 Zephyr OS 开发 IoT 系统、现代化现有应用程序还是支持团队的专业成长,我都致力于提供稳健且高效的解决方案,适应每个项目的具体需求。

我可以在艾克斯普罗旺斯周边或完全远程工作。

掌握 TypeScript 条件类型