TypeScript 里的 Type Guard 是什么

这篇写给前端新手。

如果你刚接触 TypeScript,看到下面这种写法时,八成会懵:

ts 复制代码
(item): item is SomeType => Boolean(item.id)

这东西叫 type guard。中文可以理解成"类型守卫"或者"类型保护"。

说人话就是:

它是一个告诉 TypeScript 的方法:

"如果这个判断通过了,你就可以把这个值当成更具体的类型来用。"

先理解一个核心问题

TypeScript 经常会遇到这种情况:

ts 复制代码
type User = {
  id?: string;
  name?: string;
};

const list: User[] = [
  { id: '1', name: 'A' },
  { name: 'B' },
];

这里 idname 后面有 ?,意思是它们可能不存在。

所以 TypeScript 会很谨慎。哪怕你心里知道某个值大概率有 id,它也不会随便相信你。

没有 type guard 时会怎样

ts 复制代码
const validUsers = list.filter((item) => Boolean(item.id));

这行代码在运行时没问题,它确实会把没有 id 的项过滤掉。

但是 TypeScript 往往仍然认为:

ts 复制代码
validUsers[0].id

还是"可能是 undefined"。

为什么?

因为它只看到你写了一个普通布尔判断,它不一定能完全推断出:

"过滤完以后,这个数组里的每一项都一定有 id。"

type guard 是怎么帮忙的

这时候可以这样写:

ts 复制代码
const validUsers = list.filter(
  (item): item is { id: string; name?: string } => Boolean(item.id)
);

这里最重要的是:

ts 复制代码
item is { id: string; name?: string }

这句话是对 TypeScript 说的,不是给浏览器看的。

它的意思是:

"如果这个函数返回 true,那 item 就可以被当成一个 id 一定存在的对象。"

这样后面你再访问:

ts 复制代码
validUsers[0].id

TypeScript 就会更放心,因为它知道这里的 id 已经被"缩窄"成 string 了。

它和普通判断有什么区别

看下面这两部分:

ts 复制代码
Boolean(item.id)

这是运行时判断。程序真正执行的是它。

ts 复制代码
item is { id: string; name?: string }

这是类型提示。它主要是写给 TypeScript 编译器看的。

所以可以把一整句拆开理解:

  • 前半句负责"真的检查"
  • 后半句负责"告诉 TypeScript 检查完以后该怎么看这个值"

什么时候 type guard 很有用

最常见是下面这几类情况:

  1. 一个字段是可选的,你过滤后想让 TypeScript 知道它现在一定存在。
  2. 一个值可能是多种类型中的一种,你想先判断再安全使用。
  3. 你在 filterfindif 里做了检查,但 TypeScript 还不够确定。

比如:

ts 复制代码
type Data = string | number;

function printLength(value: Data) {
  if (typeof value === 'string') {
    console.log(value.length);
  }
}

这里 typeof value === 'string' 其实也是一种 type guard。

它告诉 TypeScript:

"进到这个 if 里面后,value 就是字符串。"

什么时候它是多余的

如果一个值本来就已经是那个类型了,那再写一遍 type guard 就没有太大意义。

比如:

ts 复制代码
type Category = {
  frameworkId: string;
  categoryId: string;
};

const categories: Category[] = [];

这里数组里的每一项本来就是:

ts 复制代码
{
  frameworkId: string;
  categoryId: string;
}

那你再写:

ts 复制代码
(item): item is Category => Boolean(item.frameworkId && item.categoryId)

就有点像在说:

"如果判断通过,那它就是它自己。"

这时 reviewer 往往会觉得这段写法太重了,因为它没有提供新的类型信息。

一句最实用的判断标准

你可以这样问自己:

"我写这个 type guard 之后,TypeScript 知道的类型信息,比之前更多了吗?"

如果答案是:

  • 是,那它通常有价值
  • 不是,那它大概率只是写复杂了

新手可以先记住这三种

1. typeof

ts 复制代码
if (typeof value === 'string') {
  // 这里 value 是 string
}

2. instanceof

ts 复制代码
if (error instanceof Error) {
  // 这里 error 是 Error
}

3. 自定义 item is Xxx

ts 复制代码
const result = list.filter(
  (item): item is { id: string } => Boolean(item.id)
);

这个最灵活,但也是最容易被滥用的。

最后一句总结

type guard 不是为了让代码"看起来更高级",而是为了在类型不够明确的时候,帮 TypeScript 正确缩窄类型。

如果原来的类型已经很明确,再加一个 type guard,通常只会让代码更绕。

相关推荐
Amumu1213816 分钟前
Js:正则表达式(二)
开发语言·javascript·正则表达式
Sgf22737 分钟前
ES8(ES2017)新特性完整指南
开发语言·javascript·ecmascript
Cobyte3 小时前
1.基于依赖追踪和触发的响应式系统的本质
前端·javascript·vue.js
老神在在0014 小时前
【Selenium 自动化精讲】浏览器弹窗与登录界面的本质区别 & 实操指南
javascript·学习·selenium·测试工具·自动化
拾贰_C4 小时前
【Ubuntu | install | 安装软件】 Ubuntu软件安装多种方式以及卸载
linux·运维·ubuntu
前端小咸鱼一条4 小时前
16.迭代器 和 生成器
开发语言·前端·javascript
前端小阳5 小时前
JavaScript原型链
javascript
早點睡3905 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-collapsible
javascript·react native·react.js
前端Hardy5 小时前
别再手写代码了!2026 前端 5 个 AI 杀招,直接解放 80% 重复劳动(附工具+步骤)
前端·javascript·面试
SuperEugene5 小时前
Element Plus/VXE-Table UI 组件库规范:统一用法实战,避开样式冲突与维护混乱|工程化与协作规范篇
前端·javascript·vue.js·ui·前端框架·element plus·vxetable