TS 高级类型:Partial 使用及实现原理

在用 TypeScript 写项目的时候,难免会碰到各种类型之间需要转换的情况。比如某个对象类型,我们只想用它的一部分,或者想让它的属性变成可选的。这时候,TS 自带的工具类型就非常好用!

这个系列我们就来聊聊那些常用的 TS 内置工具类型,让你写类型更轻松、更优雅。

第一位登场的是——Partial

什么是 Partial

在 TypeScript 中,Partial 是一个非常实用的工具类型(Utility Type),它的作用就是:把某个类型的所有属性变成可选的。

换句话说,如果你原本有一个类型里所有字段都是必填的,用 Partial 包一下之后,就可以只写其中一部分字段了,非常适合用在更新、配置等场景中。

它的定义如下:

 

ts

代码解读

复制代码

type Partial<T> = { [P in keyof T]?: T[P]; };

✨ 应用场景

Partial 在实际开发中非常常见,尤其适用于以下几个场景:

  1. 处理部分更新:比如你有一个完整的用户类型,但在更新时,往往只需要改一两个字段。这时候就不需要手动把每个字段都变成可选了,直接用 Partial<User> 更方便。

  2. 设置默认值再覆盖:有时候你会先定义一份默认配置,然后根据用户传入的值来覆盖。使用 Partial 可以让这些覆盖的属性不是必填的。

  3. 配置对象参数:当你写的函数接受一个配置对象作为参数,但又不希望强制调用方提供所有配置项,Partial 就很适合让这些参数都变成可选的。

🔧 基本使用

来看一个简单的例子:

 

ts

代码解读

复制代码

interface User { id: number; name: string; age: number; }

现在我们有一个完整的用户对象:

 

ts

代码解读

复制代码

const user: User = { id: 1, name: "Moment", age: 18, };

接下来我们写一个更新函数,只更新用户的部分信息:

 

ts

代码解读

复制代码

function updateUser(user: User, updatedProperties: Partial<User>): User { return { ...user, ...updatedProperties }; } const updatedUser = updateUser(user, { age: 20 }); console.log(updatedUser); // { id: 1, name: 'Moment', age: 20 }

你会发现,只传入了 age 字段,也能成功更新。这就是 Partial 的魅力。

✅ 不用手动把 nameid 标成可选,TypeScript 自动帮你搞定了。

最终运行结果如下图所示:

🧠 实现原理

Partial 的实现,其实用到了 TypeScript 中两个核心特性:映射类型(Mapped Types) 和 索引类型(Index Types)。

首先我们对 Partial 的定义回顾:

 

ts

代码解读

复制代码

type Partial<T> = { [P in keyof T]?: T[P]; };

逐步拆解来看:

  • keyof T:取出类型 T 的所有键,例如 User 的话就是 'id' | 'name' | 'age'

  • [P in keyof T]:对这些键进行遍历,也就是“映射”。

  • ?: T[P]:将每个属性变成可选,且类型保持原样。

我们再来对索引类型简单回顾:

 

ts

代码解读

复制代码

interface User { id: number; name: string; age: number; } type UserKeys = keyof User; // 'id' | 'name' | 'age' type UserIdType = User["id"]; // number

结合这两个特性,Partial 就能把一个类型“转换”为一个所有字段都可选的新类型,而你只需要一行代码就能搞定,非常方便。

复杂场景:表单编辑(Form 编辑场景)

假设你正在开发一个用户管理系统,用户的资料可以编辑,但不一定每次都更新所有字段,而且用户资料的结构比较复杂,包含嵌套对象。

用户类型定义:

 

ts

代码解读

复制代码

interface Address { city: string; street: string; } interface UserProfile { id: number; name: string; age: number; email: string; address: Address; }

你现在有一个编辑页面,只需要让用户填写他们想更新的字段,比如修改邮箱、改地址,但不强制填写所有信息。这时候如果你直接用 UserProfile,就会强制所有字段都必填,非常不灵活。

于是,你可以写一个更新函数,使用 Partial 来支持“只更新部分字段”的能力:

 

ts

代码解读

复制代码

function updateProfile( profile: UserProfile, updates: Partial<UserProfile> ): UserProfile { return { ...profile, ...updates, // 注意:如果 updates.address 存在,也需要做浅合并 address: { ...profile.address, ...updates.address, }, }; }

如下使用示例:

 

ts

代码解读

复制代码

const originalProfile: UserProfile = { id: 1, name: "Moment", age: 30, email: "alice@example.com", address: { city: "Shanghai", street: "中山街道", }, }; // 只修改 email 和 address.city const updated = updateProfile(originalProfile, { email: "Moment@Moment.com", address: { city: "Beijing", }, }); console.log(updated); // 输出: // { // id: 1, // name: "Alice", // age: 30, // email: "newalice@example.com", // address: { // city: "Beijing", // street: "123 Main St", // } // }

总结

Partial<T> 是 TypeScript 提供的工具类型,用于将某个类型的所有属性变为可选。它非常适合用于处理对象的部分更新配置对象参数默认值合并等场景。使用 Partial 可以让代码更灵活,避免手动修改每个字段为可选。它的实现基于映射类型和索引类型,是 TS 类型系统中最常用也最基础的工具之一。

原文:https://juejin.cn/post/7493415712120782900

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值