TypeScript 类型设计——构建健壮代码的基石

给大家推荐一本书:《Effective TypeScript》

在《Effective TypeScript》的第四篇中,类型设计被视为构建健壮、可维护TypeScript代码的核心环节。作者Dan Vanderkam通过62个实践方法中的关键条款,深入剖析了如何通过类型设计提升代码的安全性和可读性。以下是对该篇章核心内容的提炼与扩展。

1. 倾向选择总是代表有效状态的类型

类型设计应优先反映业务逻辑中的有效状态,而非无效或中间状态。例如,在处理用户登录流程时,应定义User类型为包含idname等字段的完整对象,而非仅包含email的临时状态。
实践建议

  • 使用never类型或联合类型(如User | null)明确表示无效状态。
  • 避免在类型中暴露内部实现细节(如_isLoading等私有字段)。

2. 宽进严出:输入宽容,输出严格

函数设计应遵循"宽进严出"原则,即接受尽可能宽泛的输入类型,但返回严格限定的输出类型。

例如,一个处理用户输入的函数应接受string | number类型,但返回经过验证的string类型。

实践建议

  • 使用泛型或条件类型动态调整输入/输出类型。
  • 通过运行时校验(如zod库)确保输入符合预期。

3. 避免在文档中重复类型信息

类型声明本身即文档,应避免在注释中重复类型信息。例如,以下代码是冗余的:

js 复制代码
/**
 * @param {string} name - 用户名称
 */
function greet(name: string) { ... }

实践建议

  • 使用TSDoc注释描述类型无法表达的业务逻辑(如参数约束)。
  • 对复杂类型,可通过类型别名或接口提升可读性。

4. 将空值推到类型边界

空值(null/undefined)应作为类型的边界条件处理,而非混入核心逻辑。例如,一个返回用户信息的函数应明确返回User | null,而非在内部处理空值。

实践建议

  • 使用可选链操作符(?.)和空值合并操作符(??)简化空值处理。
  • 对可能为空的字段,使用Partial<T>或自定义工具类型(如Nullable<T>)。

5. 优选接口的联合,而非联合的接口

当需要表示多个可能的状态时,优先使用接口的联合(如type State = Loading | Success | Error),而非联合的接口(如interface LoadingState { ... })。

实践建议

  • 使用discriminated union(可辨识联合)通过共同字段(如type)区分状态。
  • 对复杂状态,可结合typeinterface实现更灵活的设计。

6. 选择更精确的字符串类型的替代类型

避免直接使用string类型,应优先选择更精确的替代类型。例如:

js 复制代码
type Email = string; // 不推荐

type Email = `${string}@${string}.${string}`; // 更精确(需TypeScript 4.1+)

实践建议

  • 使用字符串字面量类型(如type Status = 'active' | 'inactive')。
  • 对复杂模式,可结合正则表达式或第三方库(如io-ts)进行验证。

7. 从API和规范生成类型

类型应直接从API文档或规范生成,而非手动编写。例如,通过openapi-typescript等工具从OpenAPI规范生成类型。

实践建议

  • 使用d.ts文件或@types包管理第三方库的类型。
  • 对自定义API,编写类型生成脚本(如基于JSON Schema)。

8. 使用问题域语言命名类型

类型名称应直接反映业务领域概念,而非技术实现。例如,将UserList改为TeamMembers,将DataStore改为CustomerDatabase

实践建议

  • 避免使用通用名称(如ManagerHandler),除非它们是领域术语。
  • 通过团队讨论统一术语,避免命名歧义。

9. 考虑加"烙印"实现名义类型

当需要区分本质相同但语义不同的类型时,可通过"烙印"(Brand)模式实现名义类型。例如:

js 复制代码
type UserId = string & { __brand: 'UserId' };
function createUserId(id: string): UserId {
 return id as UserId;
}

实践建议

  • 使用zodio-ts等库内置的名义类型支持。
  • 对复杂场景,可结合TypeScript的nominal typing技巧(如私有字段)。

总结

类型设计是TypeScript开发的核心技能。通过遵循"有效状态优先""宽进严出""避免重复类型信息"等原则,开发者可以构建出更安全、更易维护的代码。同时,结合工具链(如类型生成、运行时校验)和领域驱动设计(DDD)思想,可以进一步提升类型设计的表达力和实用性。

《Effective TypeScript》的第四篇不仅提供了具体的实践方法,更传递了一种以类型为中心的编程思维。掌握这些技巧,将帮助开发者从"使用TypeScript"跃升至"精通TypeScript"。

相关推荐
AI视觉网奇5 小时前
rknn yolo11 推理
前端·人工智能·python
gplitems1235 小时前
Gunslinger – Gun Store & Hunting WordPress Theme: A Responsible
开发语言·前端·javascript
wyzqhhhh8 小时前
less和sass
前端·less·sass
Nan_Shu_6149 小时前
学习:uniapp全栈微信小程序vue3后台-额外/精彩报错篇
前端·学习·微信小程序·小程序·uni-app·notepad++
excel10 小时前
Vue3 中的双向链表依赖管理详解与示例
前端
前端小白从0开始11 小时前
Chrome DevTools高级用法:性能面板内存泄漏排查
前端·chrome·chrome devtools
EveryPossible11 小时前
带有渐变光晕
前端·javascript·css
jojo是只猫11 小时前
Vue 3 开发的 HLS 视频流播放组件+异常处理
前端·javascript·vue.js
卓码软件测评11 小时前
第三方软件登记测试机构:【软件登记测试机构HTML5测试技术】
前端·功能测试·测试工具·html·测试用例·html5
CS Beginner11 小时前
【html】canvas实现一个时钟
前端·html