4.any和 unknown 副本.md 来源:https://my.feishu.cn/file/XsYRbfDMfo9LORxxglpcx0Jgnxh 采集状态:已完成正文采集;已从查看代码模式逐行提取,行号 1 至 95 连续,并核对滚动到底。 ## TypeScript 中的灵活性与安全性:`any` vs `unknown` 在探索 TypeScript 强类型系统的旅程中,我们总会遇到一些特殊情况。比如,当处理来自第三方库、API 响应或用户输入的数据时,我们可能无法在开发阶段预知一个值的具体类型。 为了应对这些动态和不确定的场景,TypeScript 提供了两个特殊的类型:`any` 和 `unknown`。它们都允许我们绕过常规的类型检查,但其背后的设计哲学和安全级别却截然不同。 ### `any`:无所不能的“逃生舱” `any` 类型是 TypeScript 中的一个“逃生舱”。当我们为一个变量标注为 `any` 类型时,实际上是在告诉 TypeScript 编译器:“**请不要对这个变量进行任何类型检查。**” 这赋予了我们极大的灵活性,让这个变量的行为退回到了纯粹的 JavaScript 模式。我们可以对它进行任何操作,包括赋任何类型的值、调用任何方法、访问任何属性,无论这些操作是否合理,编译器都不会提出任何异议。 **代码示例:** ```typescript let flexible: any = 4; // 我们可以随意改变它的类型 flexible = "Now I'm a string"; flexible = true; // 我们可以调用任何方法,即使它不存在 // 编译器不会报错,但会在运行时抛出错误 flexible.thisMethodDoesNotExist(); // 我们可以访问任何属性 console.log(flexible.someProperty); ``` ### `any` 的问题:一把双刃剑 `any` 带来的便利是显而易见的,它让我们可以快速地在 TypeScript 项目中集成那些没有类型定义的旧有 JavaScript 代码。 然而,这种便利是有代价的。过度使用 `any` 会严重削弱 TypeScript 的核心优势——**类型安全**。它像一个“类型黑洞”,会污染与之交互的其他变量的类型推断。一个 `any` 类型的值,可以被赋值给任何类型的变量,这就在类型系统中打开了一个缺口,可能会在应用的深层引发难以追踪的运行时错误。 因此,我们的基本原则应该是:**尽可能避免使用 `any`**。它应该是我们最后的选择,而不是常规手段。 ### `unknown`:`any` 的类型安全替代方案 认识到 `any` 的潜在风险后,TypeScript 3.0 引入了一个更优秀的解决方案:`unknown` 类型。 `unknown` 和 `any` 一样,可以接收任何类型的值。但它们之间有一个根本性的区别: > `unknown` 类型的变量,在没有被**明确地检查和断言**其类型之前,你**不能**对它进行任何操作。 `unknown` 就像一个需要开箱检查的神秘包裹。你知道你收到了一个东西(`unknown`),但在确认它到底是什么(通过类型检查)之前,你不能使用它。 **代码示例:** ```typescript let mystery: unknown = "A secret message"; // 错误:对象类型为 "unknown"。 // 我们不能直接调用一个 string 方法 // mystery.toUpperCase(); // 错误:对象类型为 "unknown"。 // 我们不能把它赋值给一个已知类型的变量 // let message: string = mystery; ``` 如上所示,TypeScript 阻止了我们对 `unknown` 类型的值进行任何不安全的操作。 ### 如何正确使用 `unknown` 要使用 `unknown` 类型的变量,我们必须先执行类型收窄(Type Narrowing),让 TypeScript 确信在某个代码块中,这个变量是某个具体的类型。 最常见的方式是使用 `typeof`、`instanceof` 或类型断言。 **代码示例:** ```typescript let mystery: unknown = "Another secret message"; // 1. 使用 typeof 进行类型收窄 if (typeof mystery === 'string') { // 在这个 if 代码块内,TypeScript 知道 mystery 是一个 string console.log(mystery.toUpperCase()); // 正确! } let maybeANumber: unknown = 100; // 2. 使用类型断言(Type Assertion) let score = maybeANumber as number; console.log(score.toFixed(2)); // 正确! ``` ### 结论:何时使用 `any` vs `unknown`? * **`unknown`**:当你确实不知道一个变量的类型,但希望在后续的操作中保持类型安全时,`unknown` 是你的首选。它强制你在使用变量前进行必要的类型检查,遵循了 TypeScript 的核心理念。 * **`any`**:仅在你需要快速绕过类型检查,并且清楚地知道这样做的风险时使用。一个典型的场景是,在一个大型 JavaScript 项目的迁移初期,为了让项目先跑起来,可能会临时使用 `any`。但长远来看,这些 `any` 都应该被逐步替换为更具体的类型或 `unknown`。 简单来说,**能用 `unknown` 就不用 `any`**。`unknown` 在提供灵活性的同时,守住了类型安全的底线,是 TypeScript 中处理未知类型值的现代且推荐的方式。