0Pricing
TypeScript Academy · 课时

定义类型构造器

将类型构造器编码为接口查找。

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

命名类型构造器

编码首先要为每个类型构造器提供一个唯一的字符串标识符,称为统一资源标识符。统一资源标识符是一种标签,在无法传递构造器本身的地方代替它。

type ArrayURI = "Array";
type OptionURI = "Option";
// Each container gets a unique string tag

一个注册表接口

我们维护一个统一的接口,将每个统一资源标识符映射到它针对给定参数 A 所产生的具体类型。这个接口就是注册表。每个键都是一个统一资源标识符,每个值都是解析后的类型。

interface URItoKind<A> {
  Array: Array<A>;
  Option: A | null;
}
// URItoKind<number>["Array"] is number[]

查找构造器

由于注册表以统一资源标识符为键,应用构造器就变成了一次索引访问。要获取“将数组构造器应用于数字”的结果,您只需对注册表进行索引。

type ArrayOfNumber = URItoKind<number>["Array"]; // number[]
type OptionOfString = URItoKind<string>["Option"]; // string | null

URIS 联合类型

有效构造器标签的集合就是注册表的键。keyof URItoKind<unknown> 会给出所有已注册统一资源标识符的联合类型,我们将其命名为 URIS。

type URIS = keyof URItoKind<unknown>; // "Array" | "Option"

声明合并扩展注册表

TypeScript 有一项强大的功能:同名接口会合并。库会利用这一点,让每个模块都能将自己的容器添加到 URItoKind,而无需编辑原始定义。

interface URItoKind<A> {
  Tree: { value: A; children: Array<A> };
}
// Now URIS also includes "Tree"

模块化容器

得益于声明合并,在一个文件中定义的容器可以将自身注册到全局。任何导入它的代码都可以在泛型抽象中使用它的统一资源标识符。这正是 fp-ts 添加选项、二选一、任务等类型的方式。

// file a.ts
interface URItoKind<A> { Either: { left: A } | { right: A } }
// file b.ts can now reference the "Either" URI

一个幽灵载体

为了以值级类型传递“是哪一种构造器”,实例会在某个属性中携带其统一资源标识符,通常是一个幽灵字段。这个字段从不保存真实值,它只为类型系统记录该标签。

interface HasURI<F extends URIS> {
  readonly _URI: F;
}
// _URI records which constructor an instance is for

将统一资源标识符与参数配对

一次构造器应用需要两样东西:统一资源标识符 F 和参数类型 A。我们会通过查找将它们组合起来,使 (F, A) 能通过注册表解析为具体类型。

type Apply<F extends URIS, A> = URItoKind<A>[F];

type A = Apply<"Array", number>;  // number[]
type B = Apply<"Option", string>; // string | null

为什么使用字符串而不是构造器

我们使用字符串,是因为 TypeScript 可以将字符串存储并比较为字面量类型,也可以用它们索引注册表。我们无法将构造器 Array 作为类型参数存储,但可以存储字面量 "Array" 并对其进行查找。

type Tag = "Array";
type Resolved = URItoKind<boolean>[Tag]; // boolean[]

查找是关键步骤

这个索引访问 URItoKind<A>[F] 是整个编码的核心。它将不可能实现的类型应用 F<A> 转换为合法的注册表查找。下一课会将它正式定义为 Kind<F, A>。

type Kind<F extends URIS, A> = URItoKind<A>[F];

type X = Kind<"Array", number>; // number[]

设置部分回顾

现在您已经拥有了各个组成部分:作为标签的统一资源标识符、将标签和参数映射到具体类型的 URItoKind 注册表、作为标签联合类型的 URIS,以及用于扩展注册表的声明合并。对注册表进行索引就可以模拟类型应用。

// URItoKind = registry, URIS = valid tags,
// URItoKind<A>[F] = "apply constructor F to A"

快速检查

测试您对注册表编码的理解。

回顾

您学会了使用字符串编码类型构造器。

  • 每个构造器都会获得一个唯一的统一资源标识符标签。
  • URItoKind<A> 将标签映射到具体类型。
  • URIS 通过 keyof 表示所有标签的联合类型。
  • 声明合并让模块能够注册新的容器。

下一步:将查找封装为轻量级的 Kind 模式。

常见问题解答

「定义类型构造器」课时是免费的吗?

是的 — 「定义类型构造器」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 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. TypeScript 中的 HKT 问题
  2. 定义类型构造器
  3. 轻量级 HKT 模式
  4. 泛型函子与映射器
← 返回 TypeScript Academy