ZetCode

TypeScript 实用类型

最后修改于 2025 年 3 月 5 日

TypeScript 实用类型是内置工具,可简化常见的类型操作。它们提供了一种简洁的方式来转换、提取或修改现有类型,而无需从头开始编写自定义类型定义。本教程将通过实际示例探讨一系列实用类型,以展示它们的实用性和多功能性。

诸如 PartialPickReturnType 等实用类型利用了 TypeScript 的高级功能(如映射类型、条件类型和推断)来满足频繁的类型需求。它们在 TypeScript 中是全局可用的,无需导入,旨在提高在从对象操作到函数分析的各种场景下的生产力和类型安全性。

Partial

Partial<T> 实用类型使类型的​​所有属性都变为可选。

partial.ts
interface User {
    name: string;
    age: number;
}

const partialUser: Partial<User> = { name: "Alice" };
console.log(partialUser.name); // Output: Alice

Partial<User> 实用类型将 User 接口转换为一个类型,其中 nameage 是可选的({ name?: string; age?: number })。这使得 partialUser 可以省略 age 而不会出现类型错误,这与原始的 User 不同,后者需要两个属性。

输出“Alice”证实了 name 属性是可访问的,而 age 保持未定义但有效。此实用类型非常适合表单更新或 API 有效负载等场景,其中仅提供部分字段,从而简化了部分对象定义。

Pick

Pick<T, K> 实用类型通过从现有类型中选择特定属性来创建一个类型。

pick.ts
interface Product {
    id: number;
    name: string;
    price: number;
}

const pickedProduct: Pick<Product, "id" | "name"> = { id: 1, name: "Laptop" };
console.log(pickedProduct.name); // Output: Laptop

Pick<Product, "id" | "name">Product 中仅使用 idname 属性构建一个新类型,得到 { id: number; name: string }pickedProduct 对象排除了 price,如果包含它(例如 price: 100)将导致类型错误。

输出“Laptop”显示了所选属性的使用情况。此实用类型对于创建类型的子集很有用,例如在仅将相关字段传递给函数或组件时,从而提高类型精度并减少样板代码。

Omit

Omit<T, K> 实用类型通过从现有类型中排除特定属性来创建一个类型。

omit.ts
interface Item {
    id: number;
    name: string;
    category: string;
}

const omittedItem: Omit<Item, "category"> = { id: 1, name: "Book" };
console.log(omittedItem.name); // Output: Book

Omit<Item, "category">Item 生成一个不包含 category 属性的类型,得到 { id: number; name: string }omittedItem 对象符合此要求,排除了 category,并且添加它(例如 category: "Books")将导致类型检查失败。输出“Book”证实了保留的 name 属性。此实用类型通过允许排除而不是包含来补充 Pick,使其在从对象类型中删除敏感或不相关字段时非常方便。

Readonly

Readonly<T> 实用类型使类型的​​所有属性都变为只读。

readonly.ts
interface Config {
    host: string;
    port: number;
}

const config: Readonly<Config> = { host: "localhost", port: 8080 };
// config.host = "example.com"; // Error: Cannot assign to 'host' because it is read-only
console.log(config.host); // Output: localhost

Readonly<Config>Config 转换为 { readonly host: string; readonly port: number },防止初始化后修改属性。config 对象可以定义但不能更改——尝试 config.host = "example.com" 会触发编译时错误,如注释所示。输出“localhost”反映了不可变值。此实用类型非常适合定义常量或保护数据结构免遭意外更改,从而提高诸如配置管理等场景下的代码可靠性。

Required

Required<T> 实用类型使类型的​​所有可选属性都变为必需。

required.ts
interface OptionalUser {
    name?: string;
    age?: number;
}

const requiredUser: Required<OptionalUser> = { name: "Bob", age: 30 };
console.log(requiredUser.age); // Output: 30

Required<OptionalUser>OptionalUser 的可选属性(name?: stringage?: number)转换为必需属性({ name: string; age: number })。requiredUser 对象必须包含 nameage——省略其中任何一个(例如 { name: "Bob" })都会导致类型错误。

输出 30 证实了 age 的存在。此实用类型对于强制执行完整性非常有用,例如确保在可选阶段之后,最终数据结构中提供了所有字段。

Record

Record<K, T> 实用类型创建一个具有类型 K 的键和类型 T 的值的类型。

record.ts
type Status = "success" | "error" | "pending";

const statusMessages: Record<Status, string> = {
    success: "Operation completed",
    error: "Something went wrong",
    pending: "In progress"
};

console.log(statusMessages.success); // Output: Operation completed

Record<Status, string> 构建一个类型,其中来自 Status 联合("success" | "error" | "pending")的每个键都映射到一个 string 值,得到 { success: string; error: string; pending: string }statusMessages 对象必须定义所有键并具有字符串值,并且缺少键(例如省略 pending)将导致类型检查失败。

输出“Operation completed”显示了 success 值。此实用类型非常适合创建具有类型安全键和值的字典或查找表,从而简化诸如状态码到消息的映射。

ReturnType

ReturnType<T> 实用类型提取函数类型的返回类型。

returntype.ts
function getName(): string {
    return "Alice";
}

type NameType = ReturnType<typeof getName>;
const name: NameType = "Bob";
console.log(name); // Output: Bob

ReturnType<typeof getName> 使用 typeof 来捕获函数的类型,从而推断 getName 的返回类型,即 stringNameType 别名变为 string,允许 name 被赋值为任何字符串值,例如“Bob”。输出“Bob”证实了这一点。此实用类型对于从函数派生类型而不手动指定它们非常强大,在诸如高阶函数或回调中的函数结果类型化等场景中很有用。

Exclude

Exclude<T, U> 实用类型会从可以分配给另一个类型的联合中移除类型。

exclude.ts
type Status = "success" | "error" | "pending" | "loading";

type NonErrorStatus = Exclude<Status, "error" | "loading">;
const status: NonErrorStatus = "success";
console.log(status); // Output: success

Exclude<Status, "error" | "loading"> 过滤 Status 联合("success" | "error" | "pending" | "loading"),移除 "error""loading",留下 "success" | "pending"status 变量可以是 "success""pending",但赋值 "error" 会失败。

输出“success”反映了一个有效值。此实用类型非常适合缩小联合类型,例如从更广泛的状态类型中排除错误状态,以用于特定的逻辑分支。

Extract

Extract<T, U> 实用类型会保留联合中可以分配给另一个类型的类型。

extract.ts
type Event = "click" | "hover" | "scroll" | string;

type MouseEvent = Extract<Event, "click" | "hover">;
const event: MouseEvent = "click";
console.log(event); // Output: click

Extract<Event, "click" | "hover">Event 联合("click" | "hover" | "scroll" | string)中仅保留 "click""hover",因为它们与指定的类型匹配,得到 "click" | "hover"event 变量可以是其中任何一个,但 "scroll" 或随机字符串(如 "focus")会失败(尽管原始联合中包含 string)。

输出“click”证实了一个有效的提取值。此实用类型对于隔离联合的特定子集很有用,例如从更广泛的事件类型中提取与鼠标相关的事件。

NonNullable

NonNullable<T> 实用类型会从类型中移除 nullundefined

nonnullable.ts
type Value = string | null | undefined;

const safeValue: NonNullable<Value> = "Hello";
console.log(safeValue); // Output: Hello

NonNullable<Value>Value 联合(string | null | undefined)中剥离 nullundefined,留下 stringsafeValue 变量必须是字符串——赋值 nullundefined 会导致类型检查失败。

输出“Hello”反映了这种非可空约束。此实用类型对于确保值已定义至关重要,例如在进行空值检查后或在使用已解析可空性的 API 时,从而在关键操作中增强类型安全性。

最佳实践

来源

TypeScript 实用类型文档

本教程通过实际示例介绍了 TypeScript 实用类型。使用这些内置工具来简化类型操作并增强代码安全性。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有超过十年的经验。

列出所有 TypeScript 教程