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"。

相关推荐
云小遥19 分钟前
Cornerstone3D 2.x升级调研
前端·数据可视化
李明卫杭州25 分钟前
浅谈JavaScript中Blob对象
前端·javascript
springfe010125 分钟前
Cesium 3D地图 图元 圆柱 图片实现
前端·cesium
meng半颗糖28 分钟前
vue3 双容器自动扩展布局 根据 内容的多少 动态定义宽度
前端·javascript·css·vue.js·elementui·vue3
yt9483229 分钟前
jquery和CSS3圆形倒计时特效
前端·css3·jquery
teeeeeeemo31 分钟前
CSS3 动画基础与技巧
前端·css·笔记·css3
年纪轻轻就扛不住33 分钟前
CSS3 渐变效果
前端·css·css3
Aisanyi37 分钟前
【鸿蒙开发】使用HMRouter路由的使用
前端·harmonyos
杉木笙42 分钟前
Flutter 代码雨实现(矩阵雨)DLC 多图层
前端·flutter
SouthernWind44 分钟前
Vista AI 演示—— 提示词优化功能
前端·vue.js