javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > TypeScript Type Guard

深入理解TypeScript中Type Guard

作者:十步杀一人_千里不留行

本文主要介绍了深入理解TypeScript中Type Guard,涵盖三种常见使用场景:字段过滤、类型判断判断及isXxx检查,助开发者更精准地控制类型信息,同时提升代码质量

这篇写给前端新手。

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

(item): item is SomeType => Boolean(item.id)

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

说人话就是:

它是一个告诉 TypeScript 的方法:

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

先理解一个核心问题

TypeScript 经常会遇到这种情况:

type User = {
  id?: string;
  name?: string;
};

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

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

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

没有 type guard 时会怎样

const validUsers = list.filter((item) => Boolean(item.id));

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

但是 TypeScript 往往仍然认为:

validUsers[0].id

还是“可能是 undefined”。

为什么?

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

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

type guard 是怎么帮忙的

这时候可以这样写:

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

这里最重要的是:

item is { id: string; name?: string }

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

它的意思是:

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

这样后面你再访问:

validUsers[0].id

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

它和普通判断有什么区别

看下面这两部分:

Boolean(item.id)

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

item is { id: string; name?: string }

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

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

什么时候 type guard 很有用

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

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

比如:

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 就没有太大意义。

比如:

type Category = {
  frameworkId: string;
  categoryId: string;
};

const categories: Category[] = [];

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

{
  frameworkId: string;
  categoryId: string;
}

那你再写:

(item): item is Category => Boolean(item.frameworkId && item.categoryId)

就有点像在说:

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

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

一句最实用的判断标准

你可以这样问自己:

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

如果答案是:

新手可以先记住这三种

1.typeof

if (typeof value === 'string') {
  // 这里 value 是 string
}

2.instanceof

if (error instanceof Error) {
  // 这里 error 是 Error
}

3. 自定义item is Xxx

const result = list.filter(
  (item): item is { id: string } => Boolean(item.id)
);

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

最后一句总结

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

到此这篇关于深入理解TypeScript中Type Guard 的文章就介绍到这了,更多相关TypeScript Type Guard内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文