news 2026/9/25 11:52:21

TypeScript 可选属性实战:The Concise TypeScript Book 第 13 章精读与 strictNullChecks、默认值、工具类型纵深解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TypeScript 可选属性实战:The Concise TypeScript Book 第 13 章精读与 strictNullChecks、默认值、工具类型纵深解析
  • 文档
  • 教程

【免费下载链接】typescript-book

The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.

项目地址:https://gitcode.com/gh_mirrors/typ/typescript-book
点击查看免费下载

本文以 The Concise TypeScript Book(当前开源仓库typescript-book)印尼语版第 13 章"Properti Opsional"(可选属性)为骨架,完整继承原文档的两个核心知识点——用?声明可选属性、为可选属性指定默认值——并结合仓库中strictnullchecks、type-manipulation、narrowing、object-types等章节的真实内容,深入讲解可选属性在严格空值检查下的真实类型语义、与Partial/Required工具类型的配合方式,以及在实际项目中处理"可能缺失"数据时的完整方案。

用?声明可选属性

原文档(optional-properties.md)开篇给出的定义是:对象可以通过在属性名称末尾添加问号?来指定可选属性(Optional Properties)。这是 TypeScript 类型系统中控制"某属性是否必须存在"的基础机制:

type X = { a: number; b?: number; // Optional };

这段代码定义了对象类型X:

  • a: number是必填属性——任何X类型的值都必须提供a,否则类型检查不通过;
  • b?: number是可选属性——b可以省略,也可以在提供时取任意number值。

也就是说,以下两个对象都合法:

const x1: X = { a: 1 }; // 省略可选属性 b,合法 const x2: X = { a: 1, b: 2 }; // 提供可选属性 b,合法

而同仓库中对象类型章节在介绍 interface 时给出的email?: string写法,与上面的 type alias 写法语义一致:

interface User { name: string; age: number; email?: string; }

可选属性在真实项目中最常见的场景就是描述"字段可能缺失"的结构,例如 API 响应、用户配置、表单数据等。

严格空值检查下,可选属性的类型是什么

单独理解?还不够,可选属性的实际行为与编译器选项strictNullChecks强相关。同仓库的 strictnullchecks 章节对这一选项的定义是:

strictNullChecks是 TypeScript 的编译器选项,用于强制执行严格的空值检查。当启用此选项时,变量和参数只有在被显式声明为null | undefined联合类型时,才能被赋值为null或undefined。如果变量或参数未被显式声明为可空,TypeScript 将产生错误,以防止运行时的潜在错误。

把这条规则映射到可选属性上:

  1. 未开启strictNullChecks时,undefined和null是任何类型的子类型,因此读取x.b几乎不会出现类型层面的报错,空值问题被"静默"掩盖;
  2. 开启strictNullChecks时,可选属性b?: number在语义上等价于"该属性可能缺失"。此时从对象上读取b,其类型会被视为number | undefined,任何把b直接当number使用的地方(比如直接参与算术运算)都会报错,逼迫开发者先处理"缺失"分支。

这正是原文档第二个例子必须引入"默认值"的原因——只有处理了undefined的可能性,可选属性才能安全参与计算。

为可选属性指定默认值(解构默认值)

原文档给出的第二个核心示例是:当属性是可选的时,可以指定默认值。其完整代码如下:

type X = { a: number; b?: number; }; const x = ({ a, b = 100 }: X) => a + b;

这里的关键技术是参数解构中的默认值(destructuring default value),其语义是:

  • 当传入对象的b不存在(即调用方省略了该可选属性)时,b取默认值100;
  • 当b被显式传入且值为undefined时,同样回退到100;
  • 当b被传入具体数字时,使用传入值。

对应的调用示例如下:

console.log(x({ a: 1 })); // 101 (b 缺失,回退到 100) console.log(x({ a: 1, b: 2 })); // 3 (使用传入的 b)

这样一来,函数体内部的a + b中b的类型收窄为确定的number,在strictNullChecks开启时也能通过类型检查。这种"可选属性 + 解构默认值"的组合,本质上是把b = b ?? 100这类手动空值兜底前置到了参数声明处,代码更紧凑、契约更清晰。

需要注意默认值的触发条件是"属性缺失或值为undefined",而不是 falsy:如果调用方显式传入b: 0,函数会使用0而不是回退到100。这与 JavaScript 解构默认值的标准语义一致。

可选属性与类型注解的配合规范

可选属性最常出现在对象类型的声明中,而类型注解章节给出的通用建议对含可选属性的代码同样适用:考虑对签名(signature)进行类型注解,但不在函数体内局部变量上注解,并且始终给对象字面量加上类型。

结合可选属性,一个典型的"签名带注解 + 默认值兜底"的完整写法是:

type Config = { host: string; port?: number; // 可选属性 timeout?: number; // 可选属性 }; const startServer = ({ host, port = 8080, timeout = 3000 }: Config): string => { return `listening on ${host}:${port} (timeout ${timeout}ms)`; };

这里所有可选属性都通过解构默认值获得了确定类型,返回值注解string则符合该章节"对复杂函数写明返回类型"的建议。

用工具类型批量控制可选性:Partial<T> 与 Required<T>

原文档的?是逐属性手工标记,而在处理"已有类型的整体可选化/必选化"时,类型操作章节中的两个内置工具类型更为高效:

Partial<T>——构造一个所有属性 T 都被设为可选的类型:

type Person = { name: string; age: number; }; type A = Partial<Person>; // { name?: string | undefined; age?: number | undefined; }

Required<T>——构造一个所有属性 T 都被设为必选的类型(与Partial正好互逆):

type Person = { name?: string; age?: number; }; type A = Required<Person>; // { name: string; age: number; }

这两个工具类型正是"可选属性"概念的类型级批量操作:Partial<Person>等价于把Person的每个属性名后自动加上?,Required<T>则反向去除可选标记。它们在实际开发中最常用的两个场景:

  1. 更新接口/表单场景:数据库更新、表单局部提交通常只携带部分字段,参数类型写作Partial<User>即可精确表达"所有字段均可选";
  2. 从宽松类型收紧:当某个中间数据结构大量使用可选属性时,在边界处用Required<...>强制补全,避免undefined向下游扩散。

从该章节给出的结果注释(如{ name?: string | undefined; ... })还可以印证前文所述:开启严格空值检查时,可选属性展开后的类型确实显式携带了| undefined。

可选属性的读写语义与 readonly 的对比

理解可选属性时容易与只读属性混淆,这里对照仓库中的相邻章节说明二者正交:

  • 可选(?)控制的是属性是否存在,见原文档 optional-properties.md;
  • 只读(readonly)控制的是属性能否被重新赋值,readonly-properties 章节的说明是:readonly修饰符确保属性"不能被重新赋值,但不提供完全的不可变性保证",且Readonly<T>工具类型可将整个类型的属性批量设为只读。

两者可以自由组合,例如"可能存在且存在后不可修改"的字段:

type Connection = { id: string; endpoint?: string; // 可选 createdAt: readonly { // 必填,但对象本身声明了只读约束的字段 value: number; }; };

读取可选属性前的类型收窄

即便声明了可选属性,直接读取它仍会带着undefined的可能。类型收窄(narrowing)章节列举的多种收窄手段对可选属性同样有效,其中最常用的是基于 truthiness 的收窄:

const toUpperCase = (name: string | null) => { if (name) { return name.toUpperCase(); } else { return null; } };

对应到可选属性,典型写法有两种:

const config: X = { a: 1 }; // 方式一:显式判空 if (config.b !== undefined) { console.log(config.b + 1); // b 已收窄为 number } // 方式二:nullish coalescing(??)兜底 const value = config.b ?? 0;

配合这些手段,"可选属性 → 判空/默认值 → 收窄为确定类型"就形成了处理可能缺失数据的标准链路。

小结与延伸阅读

回到原文档的两个核心结论并加以纵深:

  1. 声明:在属性名后加?即可声明可选属性(b?: number),该属性可整体缺失;
  2. 默认值:在函数参数解构中使用b = 100形式的默认值,可让缺失或为undefined的可选属性回退到确定值,从而安全参与后续计算;
  3. 纵深:在strictNullChecks开启时,可选属性的读取类型携带| undefined,需要通过判空、??或解构默认值收窄;批量场景则交给Partial<T>/Required<T>工具类型。

如需继续深入类型系统,建议按以下仓库内文档顺序阅读(均为印尼语版第 13 章周边章节):

  • 类型注解(第 12 章)
  • 只读属性(第 14 章)
  • strictNullChecks(第 19 章)
  • 类型收窄(第 21 章)
  • 对象类型(第 28 章)
  • 类型操作与工具类型(第 61 章)
  • 完整目录
  • 文档
  • 教程

【免费下载链接】typescript-book

The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.

项目地址:https://gitcode.com/gh_mirrors/typ/typescript-book
点击查看免费下载
上一篇:告别网盘限速!九大平台直链下载神器完全指南
下一篇:网盘直链下载助手:八大主流网盘高速下载的终极解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 11:52:14

Keiko:一个缺乏明确指代的技术名称解析

项目标题“Keiko”目前未提供任何有效上下文——无项目正文、无关键词列表、无摘要描述&#xff0c;亦无实际可检索的公开网络热词指向明确技术实体、文化符号或行业产品。在中文互联网语境中&#xff0c;“Keiko”本身是日语罗马音拼写&#xff08;けいこ&#xff09;&#xf…

作者头像 李华
网站建设 2026/9/25 11:51:20

Dll2C反编译工具实战:从DLL导出表到C/C++代码还原

简介&#xff1a;这套压缩包面向 C 动态链接库反编译场景&#xff0c;提供 Dll2C / Dll2Cxx 工具及其配套工程示例&#xff0c;面向需要分析第三方 DLL、定位函数逻辑或恢复丢失源码的 C 开发者与逆向工程爱好者&#xff0c;尤其适合对 PE/二进制结构有基础但缺乏现成工具链的读…

作者头像 李华
网站建设 2026/9/25 11:42:06

桌面端CRM选型复盘:从Excel数据孤岛到团队高效协作

接手团队的第一周&#xff0c;我翻遍了所有人的工作电脑&#xff0c;发现一个触目惊心的事实&#xff1a;二十多个销售和售后&#xff0c;客户资料分别躺在Excel、微信收藏、纸质便签和各自的手机通讯录里。离职的销售带走了一个大客户的全部上下文&#xff0c;售后服务每天要重…

作者头像 李华