包阅导读总结
1. `TypeScript`、`Type Predicates`、`Type Narrowing`、`Return Type`、`Automatic Inference`
2. 本文主要介绍了 TypeScript 中的类型断言(Type Predicates),解释了其作用和优势,对比了 TypeScript 5.5 前后的情况,指出它能解决类型收窄问题,提高类型检查的准确性。
3.
– 什么是 Type Predicates
– 是 TypeScript 中有趣的语法特性,看起来像肯定句,能更好控制类型检查。
– Type Predicates 解决的问题
– 举例说明没有 Type Predicates 时会出现类型无法收窄的错误。
– 解决方案
– 通过特定的返回类型创建用户自定义的类型守卫。
– TypeScript 5.5 之前
– 不指定返回类型或指定为 boolean 会导致错误。
– TypeScript 5.5 之后
– 可自动推断 Type Predicates,若不满意仍可手动编写。
– 进一步学习
– 提供了官方指南供有兴趣深入了解的读者参考。
思维导图:
文章地址:https://www.freecodecamp.org/news/what-are-type-predicates-in-typescript/
文章来源:freecodecamp.org
作者:Ashutosh Biswas
发布时间:2024/9/10 15:43
语言:英文
总字数:1001字
预计阅读时间:5分钟
评分:86分
标签:TypeScript,类型谓词,TypeScript 5.5,类型收窄,TypeScript 开发
以下为原文内容
本内容来源于用户推荐转载,旨在分享知识与观点,如有侵权请联系删除 联系邮箱 media@ilingban.com
Type predicates are an interesting syntactical feature in TypeScript. While they appear in the same place as return type annotations, they look more like short affirmative sentences than typical annotations. This gives you greater control over type checking.
With the release of TypeScript 5.5, working with type predicates has become more intuitive now because it can infer them automatically in many cases. But if you’re navigating slightly older code-bases, you’re likely to encounter handwritten type predicates more often.
In this article, we will briefly explore what type predicates are and why they are useful. Let’s start by looking at the problem they solve.
The Problem
The best way to understand the usefulness of type predicates, I believe, is by noticing the problems that arise when we don’t have them:
function isString(value: unknown): boolean { return typeof value === "string";}function padLeft(padding: number | string, input: string) { if (isString(padding)) { return padding + input; } return " ".repeat(padding) + input; }
Here, the return type of isString
is set to boolean
, and we use it in a function called padLeft
to add padding to the left of an input string. The padding
can be either a given string or a specified number of space characters.
You might be wondering why I hard-coded the return type to boolean
. This is to illustrate the problem. If you don’t add any return type annotation and use the latest version of TypeScript, you won’t notice any issue here. For now, bear with me – we’ll discuss the version-related differences shortly.
The function will work smoothly at runtime, but TypeScript cannot perform any type narrowing with isString
. As a result, the type of padding
remains string | number
both inside and outside the if
statement. This leads to a conflict with repeat
‘s expectation for its first argument, causing the type error.
The Solution: Enter Type Predicates
Even if you are unfamiliar with the term predicate, you have likely used them before. Predicates in programming are simply functions that return a boolean to answer a yes/no question. Several JavaScript built-in array methods, such as filter
, find
, every
, and some
, use predicates to help with decision-making.
Type predicates are a way to make predicates more useful for type narrowing. We can fix the problem by using a type predicate as the return type:
function isString(value: unknown): value is string { return typeof value === "string";}
Here the type predicate is value is string
. It is saying three things:
-
The function is a predicate. So TypeScript will show an error if you try to return anything other than a Boolean value.
-
If it returns
true
, thenvalue
is of type string. -
If it returns
false
, thenvalue
is not of type string.
Type predicates let you create user-defined type guards. Type guards are logical checks that let you refine types to more specific types, aka narrow them. So, the above function is also a user-defined type guard.
Here is the full code:
function isString(value: unknown): value is string { return typeof value === "string";}function padLeft(padding: number | string, input: string) { if (isString(padding)) { return padding + input; } return " ".repeat(padding) + input; }
Here, TypeScript correctly narrows the type of padding
inside the if
statement and outside of it.
Now let’s briefly look at how type predicates worked before TypeScript 5.5 and what this version has improved.
Type Predicates Before TypeScript 5.5
In our previous example, if we don’t specify any return type, it will be inferred as boolean
:
function isString(value: unknown) { return typeof value === "string";}function padLeft(padding: number | string, input: string) { if (isString(padding)) { return padding + input; } return " ".repeat(padding) + input; }
As a result, we have the same error as when we manually wrote the return type boolean
. Here is the TypeScript playground link for the above code fragment. Go and hover of the functions or variables for a better feeling of the types. Then see how writing the type predicate solves the problem.
If we don’t specify the type predicate, using methods like filter
can also result in incorrect type detection:
function isString(value: unknown) { return typeof value === "string";}const numsOrStrings = [1, 'hello', 2, 'world'];const strings = numsOrStrings.filter(isString);
Now let’s see how TypeScript 5.5 improves the situation.
Type Predicates After TypeScript 5.5
One of the top features of TypeScript 5.5 is it can infer type predicates by analyzing the function body. So if you are using TypeScript 5.5 or later, you don’t have to write the type predicate as the return type of isString
. TypeScript does it for you, and code like what you see in the example below works perfectly fine:
function isString(value: unknown) { return typeof value === "string";}function padLeft(padding: number | string, input: string) { if (isString(padding)) { return padding + input; } return " ".repeat(padding) + input; }const numsOrStrings = [1, 'hello', 2, 'world'];const strings = numsOrStrings.filter(isString);const numbers = numsOrStrings.filter((v) => !isString(v));
I haven’t yet found a situation where I’m unhappy with the automatic inference of type predicates. If you do find one, you can always write your own manually.
Further Study
In this article, we briefly explored type predicates in TypeScript. If you’re interested in learning more and understanding the edge cases, here are the official guides:
Thanks for reading! See you next time!
Cover photo background is from Mona Eendra on Unsplash