any、unknown 与类型安全
本教程共 80 篇 · 第 13 篇 · 更新于 2026-08-10 · 约 10 分钟阅读
本节目标:认清
any失去所有类型检查的代价,掌握unknown作为安全替代的正确用法,学会用类型守卫收窄类型,知道什么情况下不得已用any。
any:类型的”后门”
any 是 TypeScript 里最特殊的类型——它关闭了所有类型检查。任何值都可以赋给 any,any 也可以赋给任何类型:
let value: any = 42;
// 任意赋值:不报错
value = "hello";
value = true;
value = { name: "小明" };
// 任意操作:不报错
value.foo(); // 调用不存在的方法也不报错
value.bar = "baz"; // 访问不存在的属性也不报错
// 赋给任何类型:不报错
let name: string = value; // 哪怕 value 现在是对象
let age: number = value; // 完全没有类型检查
看到这些代码,你可能会想”这不就是 JavaScript 吗?“——对,any 就是把 TypeScript 变回 JavaScript 的开关。
any 的危害不是语法层面,而是它会蔓延。一旦有一个 any,所有跟它交互的表达式也可能失去检查:
let data: any = fetchUserData();
let username = data.name; // username 也是 any
let trimmed = username.trim(); // trimmed 也是 any
// 整条链上都没有类型检查了
TypeScript 7.0 的 strict 默认值和 any
TypeScript 7.0 默认开启 strict: true,其中包含 noImplicitAny。这意味着——如果你声明变量时既没给初始值也没写类型注解,TypeScript 会报错而不是默默推断为 any:
// TypeScript 7.0 strict 模式下
// let x; // ❌ 变量 "x" 隐式具有 "any" 类型
// 必须至少做其中一项:
let x: number; // ✅ 写了类型注解
let y = 42; // ✅ 给了初始值,推断为 number
Tip7.0 的
strict默认值会帮你堵住大量可能产生any的缺口。如果你从旧版本升级,可能会看到大量新增的noImplicitAny错误——这其实是好事,它在提醒你”这里之前是不安全的”。
unknown:安全的 “any”
unknown 是 TypeScript 引入的类型安全”任意类型”。它和 any 一样能接受任何值,但不能直接操作——必须先证明你知道它是什么。
let value: unknown = "hello";
// 可以接受任何值
value = 42;
value = true;
value = { name: "小明" };
// 但不能直接操作
// value.toUpperCase(); // ❌ value 是 unknown,不能调方法
// let name: string = value; // ❌ unknown 不能赋给 string
要用 unknown 的值,必须收窄它的类型:
let value: unknown = "hello";
// 方法一:typeof 类型守卫
if (typeof value === "string") {
// 在这个分支里,value 的类型被收窄为 string
console.log(value.toUpperCase()); // ✅ "HELLO"
}
// 方法二:instanceof 检查
if (value instanceof Date) {
console.log(value.getFullYear()); // ✅ value 是 Date
}
// 方法三:自定义类型守卫
function isString(value: unknown): value is string {
return typeof value === "string";
}
if (isString(value)) {
console.log(value.length); // ✅
}
any vs unknown 对比表
| 特性 | any | unknown |
|---|---|---|
| 接受任意类型 | ✅ | ✅ |
| 直接赋值给其他类型 | ✅ | ❌ |
| 直接访问属性/调用方法 | ✅ | ❌ |
| 类型安全 | 无 | 有(强制检查) |
| 使用场景 | 迁移旧代码、不得已时 | 处理外部数据 |
一句话记住:any 说”我不管了”,unknown 说”你得先检查”。
类型守卫:收窄 unknown
类型守卫(type guard)是在运行时验证类型的模式,让 TypeScript 在某段代码范围内知道确切的类型。处理 unknown 时最常用的有这几种:
typeof 守卫
function process(value: unknown) {
if (typeof value === "string") {
console.log(`字符串长度: ${value.length}`);
} else if (typeof value === "number") {
console.log(`数字: ${value.toFixed(2)}`);
} else if (typeof value === "boolean") {
console.log(`布尔: ${value}`);
} else {
console.log("其他类型");
}
}
真值检查
function printMessage(msg: unknown) {
if (msg) {
// 排除了 null 和 undefined
console.log(String(msg));
}
}
属性检查(in 操作符)
function getArea(shape: unknown) {
if (typeof shape === "object" && shape !== null && "radius" in shape) {
// shape 在这个分支里是 object & { radius: unknown }
console.log((shape as { radius: number }).radius);
}
}
Note类型断言
as本身不做运行时检查。上面的代码配合typeof和in做了防御,as只是在”对编译器说话”。
什么时候不得已用 any
尽管你应该尽量避免 any,但有些场景确实绕不过去:
1. 迁移 JavaScript 项目时
旧项目可能有几千个 .js 文件,一下子全加类型不现实。any 允许渐进式迁移:
// 老模块暂时没有类型声明
declare module "legacy-lib" {
export function doStuff(): any; // 暂时用 any,后续补类型
}
2. 第三方库缺少类型声明
有些 npm 包没有 @types/*,导入时会报错。临时方案是声明为 any:
declare module "untyped-package";
// 导入的类型默认为 any
3. 与动态内容交互
JSON.parse() 返回 any,因为编译时不可能知道 JSON 字符串的结构:
const data: unknown = JSON.parse(response); // 用 unknown 比 any 好
if (typeof data === "object" && data !== null && "name" in data) {
// 安全使用
}
核心原则:any 是逃生出口,不是常规通道。 如果你在业务代码里频繁写 any,大概率是设计出了问题。
可运行示例
// any 和 unknown 对比示例
// === any:失去所有检查 ===
let anything: any = "hello";
anything = 42;
// 以下操作全都不报错,但运行时可能炸
console.log("any 类型测试:");
// 如果取消注释,这些都会静默通过编译但在运行时报错:
// anything.nonExistentMethod();
// === unknown:需要检查才能用 ===
function safelyProcess(input: unknown): string {
if (typeof input === "string") {
return input.toUpperCase();
}
if (typeof input === "number") {
return input.toFixed(2);
}
if (Array.isArray(input)) {
return `数组,共 ${input.length} 项`;
}
return "未知类型";
}
console.log(safelyProcess("hello")); // "HELLO"
console.log(safelyProcess(3.14159)); // "3.14"
console.log(safelyProcess([1, 2, 3])); // "数组,共 3 项"
console.log(safelyProcess(true)); // "未知类型"
输出:
any 类型测试:
HELLO
3.14
数组,共 3 项
未知类型
小结
any 是 TypeScript 的”逃生舱”——关掉所有类型检查,代价是失去安全网。unknown 是更安全的替代:接受任意类型但要求先检查再使用。TypeScript 7.0 默认 strict 模式让隐式 any 无处遁形。如果你发现自己在频繁写 any,停下来想想是不是可以用 unknown + 类型守卫来解决问题。下一章看 void、null、undefined 和 never,四个小而精的特殊类型。