首页 / TypeScript 入门教程 / any、unknown 与类型安全

TypeScript 入门教程

any、unknown 与类型安全

本教程共 80 篇 · 第 13 篇 · 更新于 2026-08-10 · 约 10 分钟阅读

TypeScriptTypeScript 入门教程anyunknown类型安全类型守卫

本节目标:认清 any 失去所有类型检查的代价,掌握 unknown 作为安全替代的正确用法,学会用类型守卫收窄类型,知道什么情况下不得已用 any

any:类型的”后门”

any 是 TypeScript 里最特殊的类型——它关闭了所有类型检查。任何值都可以赋给 anyany 也可以赋给任何类型:

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
Tip

7.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 对比表

特性anyunknown
接受任意类型
直接赋值给其他类型
直接访问属性/调用方法
类型安全有(强制检查)
使用场景迁移旧代码、不得已时处理外部数据

一句话记住: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 本身不做运行时检查。上面的代码配合 typeofin 做了防御,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 + 类型守卫来解决问题。下一章看 voidnullundefinednever,四个小而精的特殊类型。