0Pricing
TypeScript Academy · 课时

DeepPartial 与 DeepReadonly

构建 Partial 和 Readonly 的递归版本

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

为什么需要深层实用类型

内置的 Partial 和 Readonly 只适用于一层。对于嵌套对象,您需要递归版本。

interface Config {
  db: { host: string; port: number };
  app: { name: string };
}
type Shallow = Partial<Config>;
// Shallow.db is still required — only top level is optional

实现 DeepPartial

递归映射对象属性,使每个属性变为可选属性;如果属性值是对象,则递归应用 DeepPartial。

type DeepPartial<T> = T extends object
  ? { [K in keyof T]?: DeepPartial<T[K]> }
  : T;

实际使用 DeepPartial

将 DeepPartial 应用于嵌套的配置类型,查看所有层级如何变为可选。

type PartialConfig = DeepPartial<Config>;
// PartialConfig.db?: { host?: string; port?: number }

const c: PartialConfig = { db: { host: "localhost" } };
// No error — all other fields are optional

实现 DeepReadonly

通过递归处理嵌套对象类型,将每个深度的每个属性设为 readonly。

type DeepReadonly<T> = T extends object
  ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
  : T;

实际使用 DeepReadonly

深度冻结的配置在任何层级都不能被修改。

type ReadonlyConfig = DeepReadonly<Config>;
const cfg: ReadonlyConfig = { db: { host: "localhost", port: 5432 }, app: { name: "my-app" } };
// cfg.db.port = 3000; // Error: readonly

处理深层类型中的数组

数组需要特殊处理——应递归映射元素类型,而不是将数组当作普通对象。

type DeepPartial<T> =
  T extends (infer U)[]
    ? DeepPartial<U>[]
    : T extends object
      ? { [K in keyof T]?: DeepPartial<T[K]> }
      : T;

处理原始类型

递归的基本情况必须原样返回原始类型,而不是将其包装在对象映射类型中。

type DeepReadonly<T> =
  T extends string | number | boolean | null | undefined ? T
  : T extends (infer U)[] ? ReadonlyArray<DeepReadonly<U>>
  : { readonly [K in keyof T]: DeepReadonly<T[K]> };

组合 DeepPartial 和 DeepReadonly

您可以将它们组合起来,为安全的配置修补创建深层可选且只读的类型。

type SafePatch<T> = DeepReadonly<DeepPartial<T>>;

性能注意事项

递归类型作用于非常大的对象时,可能会拖慢 TypeScript 类型检查。对于性能关键的代码,请考虑设置深度限制或采用惰性求值。

// For very deep schemas, consider using Zod or io-ts
// which provide runtime + compile-time deep typing

实际用途:React 状态修补

DeepPartial 非常适合状态修补函数,这类函数只接收大型状态对象中发生变化的子集。

function patch<T>(state: T, changes: DeepPartial<T>): T {
  return { ...state, ...changes } as T;
}

回顾:深层实用类型

DeepPartial 和 DeepReadonly 是递归映射类型,会将各自的修饰符应用于嵌套对象的每个层级。请单独处理数组,并为原始类型使用基本情况。

快速检查

DeepPartial 正确的递归基本情况是什么?

您学到的内容

您使用递归映射类型实现了 DeepPartial 和 DeepReadonly。请将数组作为特殊情况处理,并始终在基本情况下原样返回原始类型。

常见问题解答

「DeepPartial 与 DeepReadonly」课时是免费的吗?

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

「DeepPartial 与 DeepReadonly」这节课中我会学到什么?

构建 Partial 和 Readonly 的递归版本 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

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

「DeepPartial 与 DeepReadonly」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. DeepPartial 与 DeepReadonly
  2. Flatten 与 UnwrapPromise 工具类型
  3. TupleToUnion 与 UnionToIntersection
  4. 发布类型工具库
← 返回 TypeScript Academy