0Pricing
TypeScript Academy · 课时

类型级条件

使用条件类型表达式根据类型进行分支。

类型级条件 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。

类型级条件语句

类型语言通过条件类型获得了分支能力。语法 T extends U ? X : Y 的含义是:如果 T 可赋值给 U,结果就是 X,否则就是 Y。

这相当于类型级的 if / else 表达式。

type IsString<T> = T extends string ? "yes" : "no";

type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"

extends 表示可赋值

这里的测试不是相等性判断。当预期类型为 U 时,如果可以使用类型为 T 的值,则 T extends U 为真。字面量类型可以赋值给其基础类型。

type T1 = "hello" extends string ? true : false; // true
type T2 = string extends "hello" ? true : false; // false
type T3 = 42 extends number ? true : false;       // true

选择结果类型

条件类型可以让一个泛型根据输入返回不同的结构。在这里,Wrap 对数组和标量采用了不同的封装方式。

type Wrap<T> = T extends unknown[]
  ? { list: T }
  : { value: T };

type A = Wrap<number>;   // { value: number }
type B = Wrap<string[]>; // { list: string[] }

筛选为 never

一种常见技巧是在某个分支返回 never。never 表示“没有值”,稍后可以利用它从联合类型中移除成员。

type OnlyStrings<T> = T extends string ? T : never;

type A = OnlyStrings<string>; // string
type B = OnlyStrings<number>; // never

使用类型推断

真正强大的功能来自 infer 关键字。在条件类型中,infer 会引入一个新的类型变量,用来捕获匹配类型的一部分。

这里我们捕获数组的元素类型。

type ElementType<T> = T extends (infer U)[] ? U : never;

type A = ElementType<number[]>; // number
type B = ElementType<string[]>; // string

推断函数结果

您可以将 infer 放在模式中的任意位置。要提取函数返回类型,请推断箭头之后的部分。内置的 ReturnType 正是这样实现的。

type MyReturn<T> = T extends (...args: any[]) => infer R ? R : never;

type A = MyReturn<() => number>;      // number
type B = MyReturn<(x: string) => boolean>; // boolean

推断多个部分

一个条件类型可以同时引入多个 infer 变量。在这里,我们同时提取元组的第一个元素和其余部分。

type FirstRest<T> = T extends [infer H, ...infer R]
  ? { head: H; rest: R }
  : never;

type A = FirstRest<[1, 2, 3]>;
// { head: 1; rest: [2, 3] }

嵌套条件

条件类型的嵌套方式与链式 else if 完全一样。一个条件类型的 else 分支本身可以是另一个条件类型,从而形成决策阶梯。

type Describe<T> =
  T extends string ? "text" :
  T extends number ? "num" :
  T extends boolean ? "flag" :
  "other";

type A = Describe<number>; // "num"
type B = Describe<null>;   // "other"

将条件作为守卫

使用条件类型在提取数据之前验证其结构。如果输入不匹配,则回退到 never,这样就能显现误用。

type GetName<T> = T extends { name: infer N } ? N : never;

type A = GetName<{ name: string }>; // string
type B = GetName<{ age: number }>;  // never

组合条件

您可以通过嵌套条件来要求多个条件同时满足。在这里,某个类型必须既是对象,又具有 id,才能通过检查。

type RequireId<T> =
  T extends object
    ? T extends { id: unknown } ? T : never
    : never;

type A = RequireId<{ id: 1; x: 2 }>; // { id: 1; x: 2 }
type B = RequireId<{ x: 2 }>;        // never

条件类型无处不在

大多数内置工具类型底层都是条件类型:NonNullable、Extract、Exclude、Parameters 和 ReturnType。理解 extends ? : 就能掌握它们全部。

type MyNonNullable<T> = T extends null | undefined ? never : T;

type A = MyNonNullable<string | null>; // string

快速检查

测试您对条件类型和 infer 的理解。

回顾

条件类型为类型语言提供了条件分支和模式匹配。

  • T extends U ? X : Y 根据可赋值性进行分支。
  • infer 会将匹配的部分捕获到新的变量中。
  • 条件类型可以嵌套,形成决策阶梯。
  • 返回 never 可以筛选掉成员。

接下来:让条件类型递归调用自身,实现递归。

常见问题解答

「类型级条件」课时是免费的吗?

是的 — 「类型级条件」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。

「类型级条件」这节课中我会学到什么?

使用条件类型表达式根据类型进行分支。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「类型级条件」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 TypeScript Academy 课中编写并运行代码吗?

能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 作为计算语言的类型
  2. 类型级条件
  3. 类型级递归
  4. 可分配条件类型
← 返回 TypeScript Academy