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

面试导航 是一个专注于前、后端技术学习和面试准备的 免费 学习平台,提供系统化的技术栈学习,深入讲解每个知识点的核心原理,帮助开发者构建全面的技术体系。平台还收录了大量真实的校招与社招面经,帮助你快速掌握面试技巧,提升求职竞争力。如果你想加入我们的交流群,欢迎通过微信联系:yunmz777

在用 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 类型系统中最常用也最基础的工具之一。

相关推荐
中微子11 分钟前
JavaScript 防抖与节流:从原理到实践的完整指南
前端·javascript
天天向上102426 分钟前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y42 分钟前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁1 小时前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry1 小时前
Fetch 笔记
前端·javascript
拾光拾趣录1 小时前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟1 小时前
vue3,你看setup设计详解,也是个人才
前端
Lefan1 小时前
一文了解什么是Dart
前端·flutter·dart
Patrick_Wilson1 小时前
青苔漫染待客迟
前端·设计模式·架构
vvilkim1 小时前
Nuxt.js 全面测试指南:从单元测试到E2E测试
开发语言·javascript·ecmascript