七爪源码:自定义类型守卫

七爪源码:自定义类型守卫

嘿,欢迎阅读我们的 TypeScript Narrowing 系列的另一篇文章。 在这篇文章中,我将解释:

  • 类型谓词
  • 如何创建自己的警卫
  • 如何通过排除创建守卫
  • 这是我们系列的第三篇文章,如果你还没有看过之前的文章,我强烈建议你去看看,它们为收窄提供了坚实的基础。

    类型谓词

    在上一篇文章中,我们探讨了基本的类型保护运算符。 现在我想向你展示类型保护函数

    例如,如果您需要检查名为 value 的变量是否为字符串,则可以使用 typeof 运算符。 但你也可以做的是创建一个名为 isString() 的函数,它接收一个参数并在给定参数是字符串时返回 true。

    const isString = (value: any): boolean => typeof value === ‘string’;

    还记得上一篇文章中的 formatErrorMessage() 函数吗?

    const formatErrorMessage = ( value: null | undefined | string | Error | Warning): string => { const prefix = ‘Error: ‘; // If it’s falsy (null, undefined, empty string), return “Unknown” with the prefix if (!value) { return prefix + ‘Unknown’; } // If it’s a string, return the string with the prefix if (typeof value === ‘string’) { return prefix + value; } // If it’s a Warning, return the Warning.text with the prefix if (‘text’ in value) { return prefix + value.text; } // If it’s an Error, return the Error.message with the prefix if (value instanceof Error) { return prefix + value.message; } // We will never reach here throw new Error(`Invalid value type`);};interface Warning { text: string;}

    让我们从中删除 typeof 运算符并使用 isString() 代替。

    const formatErrorMessage = ( value: null | undefined | string | Error | Warning): string => { const prefix = ‘Error: ‘; // If it’s falsy (null, undefined, empty string), return “Unknown” with the prefix if (!value) { return prefix + ‘Unknown’; } // If it’s a string, return the string with the prefix if (isString(value)) { return prefix + value; } // If it’s a Warning, return the Warning.text with the prefix if (‘text’ in value) { return prefix + value.text; } // If it’s an Error, return the Error.message with the prefix if (value instanceof Error) { return prefix + value.message; } // We will never reach here throw new Error(`Invalid value type`);};interface Warning { text: string;}

    相同的代码,我们只是在一个函数中隔离了守卫,对吧? 不,它坏了。 TypeScript 没有将类型缩小为字符串,防护不起作用。

    事情是这样的,isString() 返回一个布尔值,我们知道这个布尔值的含义。

    const isString = (value: any): boolean => typeof value === ‘string’;

    这意味着参数是一个字符串。 但是 TypeScript 不知道那个布尔值是什么意思,所以让我们教它。

    与其说我们的函数返回一个布尔值,不如说我们的函数返回问题的答案:“这个参数是字符串吗?”。

    鉴于我们的参数的名称是 value,我们使用以下语法来做到这一点:value 是字符串。

    const isString = (value: any): value is string => typeof value === ‘string’;

    现在 TypeScript 知道 isString() 是一个类型保护并且我们的 formatErrorMessage() 函数可以正确编译。

    我们的 isString() 函数的返回类型不再只是一个布尔值,它是一个“类型谓词”。

    因此,要制作自定义类型保护,您只需定义一个返回类型谓词的函数。

    所有类型谓词都采用 { parameter } is { Type } 的形式。

    未知类型

    在我们继续之前的快速提示:

    如果我们使用未知类型,我们的代码会更安全,而不是在我们的自定义保护参数中使用类型 any。

    const isString = (value: unknown): value is string => typeof value === ‘string’;

    我制作了一个一分钟的视频来解释任何和未知之间的区别,链接在参考资料中。

    自定义警卫

    让我们通过将 formatErrorMessage() 函数中的所有检查转换为自定义守卫来锻炼我们的知识。

    我们已经有了字符串保护,现在我们需要警告、错误虚假类型的保护。

    错误防护

    Error 的保护非常简单,我们只是将 instanceof 操作符检查隔离在一个函数中。

    const isError = (value: unknown): value is Error => value instanceof Error;

    警戒卫士

    但另一方面,Warning 守卫并不是那么简单。

    TypeScript 允许我们使用 in 运算符,因为我们的 value 参数可以是有限数量的类型,并且它们都是对象。

    const formatErrorMessage = ( value: null | undefined | string | Error | Warning): string => { const prefix = ‘Error: ‘; // If it’s falsy (null, undefined, empty string), return “Unknown” with the prefix if (!value) { return prefix + ‘Unknown’; } // If it’s a string, return the string with the prefix if (isString(value)) { return prefix + value; } // If it’s a Warning, return the Warning.text with the prefix if (‘text’ in value) { return prefix + value.text; } // If it’s an Error, return the Error.message with the prefix if (isError(value)) { return prefix + value.message; } // We will never reach here throw new Error(`Invalid value type`);};interface Warning { text: string;}

    但是如果我们创建一个函数并说我们的参数是未知的,那么它可以是任何东西。 包括原始类型,这会引发错误,因为我们只能在对象中使用 in 运算符。

    interface Warning { text: string;}const isWarning = (value: unknown): value is Warning => ‘text’ in value; // Compilation error

    解决方案是在使用 in 运算符之前确保我们的参数是一个有效的对象。 我们还需要确保它不为空。

    interface Warning { text: string;}const isWarning = (value: unknown): value is Warning => typeof value === ‘object’ && value !== null && ‘text’ in value;

    假守卫

    对于虚假值守卫,我们首先需要定义一个类型,其值被认为是虚假的。

    type Falsy = false | 0 | -0 | 0n | ” | null | undefined;

    我在这里不包括 NaN,因为 TypeScript 中没有 NaN 类型。

    type Falsy = false | 0 | -0 | 0n | ” | null | undefined | ~~NaN~~;

    NaN 的类型是数字,并非所有数字都是假的,所以这就是我们不处理 NaN 的原因。

    typeof NaN;//=> number

    有一个提议将 NaN 添加为一种类型——以及整数、浮点数和无穷大。 我认为这很好,拥有这些类型会很有帮助。

    // Proposaltype number = integer | float | NaN | Infinity;

    我将在参考文献中留下该提案的链接。

    无论如何,现在我们有了 Falsy 类型,我们可以创建一个 falsy 值守卫。

    请记住,如果一个值在转换为布尔值时被认为是假的,那么它就是假的。 因此,要检查我们的值是否为假,我们可以使用抽象相等来查看它是否被转换为假。

    type Falsy = false | 0 | -0 | 0n | ” | null | undefined;const isFalsy = (value: unknown): value is Falsy => value == false;

    带有自定义警卫的 formatErrorMessage()

    就是这样,我们现在拥有了 formatErrorMessage() 函数所需的所有自定义守卫。

    // FUNCTIONconst formatErrorMessage = ( value: null | undefined | string | Error | Warning): string => { const prefix = ‘Error: ‘; // If it’s falsy (null, undefined, empty string), return “Unknown” with the prefix if (isFalsy(value)) { return prefix + ‘Unknown’; } // If it’s a string, return the string with the prefix if (isString(value)) { return prefix + value; } // If it’s a Warning, return the Warning.text with the prefix if (isWarning(value)) { return prefix + value.text; } // If it’s an Error, return the Error.message with the prefix if (isError(value)) { return prefix + value.message; } // We will never reach here throw new Error(`Invalid value type`);};// GUARDSconst isString = (value: unknown): value is string => typeof value === ‘string’;const isError = (value: unknown): value is Error => value instanceof Error;interface Warning { text: string;}const isWarning = (value: unknown): value is Warning => typeof value === ‘object’ && value !== null && ‘text’ in value;type Falsy = false | 0 | -0 | 0n | ” | null | undefined;const isFalsy = (value: unknown): value is Falsy => value == false;

    奖励:通过排除缩小范围

    在我们结束之前,我想向你展示一些东西。

    虚假值的列表是有限的,对吗?

    1. `false`2. `0` `-0` `0n` representations of zero3. ““ `””` `”` empty string4. `null`5. `undefined`6. `NaN` not a number

    但另一方面,真实值是无限的。 所有不虚假的价值观都是真实的。

    那么,如何为真实值创建类型保护呢?

    诚实守卫

    诀窍是排除虚假类型。

    我们不是检查我们的值是否为真,而是检查它是否_不_假。

    type Truthy = Exclude;const isTruthy = (value: T): value is Truthy => value == true;// Testconst x = ‘abc’ as null | string | 0;if (isTruthy(x)) { x.trim(); // `x: string`}

    我经常使用这个技巧,我们将在以后的文章中再次看到它。

    结论

    参考资料和其他链接如下。

    如果您还没有,请在社交媒体上点赞、订阅和关注我们。 这有助于我们成长,从而为您带来更多免费内容。 这是双赢的。

    郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
    (0)
    用户投稿
    上一篇 2022年6月12日
    下一篇 2022年6月12日

    相关推荐

    • 七位没整容的女明星,颜值爆棚快来看看她们到底是谁?

      #娱乐聚焦#赵丽颖一直都是备受大家喜爱的实力派演员,出演了众多让人印象深刻的影视作品,展现出了独特的个人风采,在时尚大片的拍摄上,也是让人格外惊艳,正如这一次的自然之灵时尚大片,颜…

      2022年6月8日
    • DNF:怎么选辟邪玉?新版本辟邪玉购买指南

      作者:冰河陨雪拳套 前言 自从 DNF 12周年庆国服推出未央幻境副本以来,其副本产出的各级别辟邪玉成为了玩家们提升伤害的一种途径。对于提升伤害来说‘技能伤害增加’类型的辟邪玉一马…

      2022年8月5日
    • python生成器(Generator)

      先解释几个易混淆的概念: 可迭代对象(Iterable) 迭代器(Iterator) 迭代(Iteration) Python中任意的对象,只要它定义了可以返回一个迭代器的__it…

      2022年6月16日
    • 《黎明之海》评测:超真实的大世界环球冒险

      《黎明之海》并非一味吸收各种玩法,而是对不同玩法分割整合,既保证了游戏玩法的全面性,又能保持玩家的体验流畅度。 大地是圆的,它是个“地球”——当麦哲伦率领船队用实际行动证明这一句话…

      2022年7月29日
    • 手写 Promise

      基础版本 我们先以观察者模式作为基石来搭建一个基础版本,实现的功能如下: 构造函数接受一个函数 exector 作为参数,该函数的第一个参数是 resolve,作用是把 Promi…

      2022年6月17日
    • 一些Python常用的函数

      abs(x)——返回一个数值的绝对值。参数可以是整数或浮点数,如果是复数,则返回复数的模 dict()——字典数据类型 bool()——布尔型数值 hash()——返回对象obje…

      2022年7月23日
    • 以法治利剑斩断APP“诱导下载”黑手

      国家互联网信息办公室6月14日发布新修订的《移动互联网应用程序信息服务管理规定》。新《规定》自2022年8月1日起施行。其中规定,应用程序提供者不得通过虚假宣传、捆绑下载等行为,通…

      2022年6月20日
    • 你还在直接用 localStorage 么?该提升下逼格了

      很多人在用 localStorage 或 sessionStorage 的时候喜欢直接用,明文存储,直接将信息暴露在;浏览器中,虽然一般场景下都能应付得了且简单粗暴,但特殊需求情况…

      2022年7月4日
    • 「技术干货」ARM64内核源码解读:mmu-gather操作

      环境: 处理器架构:arm64 内核源码:linux-5.10.50 ubuntu版本:20.04.1 代码阅读工具:vim+ctags+cscope 本文讲解Linux内核虚拟内…

      2022年6月13日
    • 评分最高的灾难电影TOP7!《后天》未进前三,你最喜欢哪一部?

      图文 丨Hi喵电影 编辑 丨Hi喵电影 气候剧变、火山海啸、瘟疫病毒、外星入侵……灾难片总有让人欲罢不能的魅力。宏大震撼的场面奇观,惊心动魄的火爆情节,让观…

      2022年7月21日

    联系我们

    联系邮箱:admin#wlmqw.com
    工作时间:周一至周五,10:30-18:30,节假日休息