You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function describePaymentMethod(method: PaymentMethod) {
switch (method.kind) {
case "cash":
// Here, method has type Cash
return "Cash";
case "paypal":
// Here, method has type PayPal
return `PayPal (${method.email})`;
case "credit":
// Here, method has type CreditCard
return `Credit card (${method.cardNumber})`;
}
}
function describePaymentMethod(method: PaymentMethod) {
if (method.kind === "cash") {
// Here, method has type Cash
return "Cash";
}
// Here, method has type PayPal | CreditCard
if (method.kind === "paypal") {
// Here, method has type PayPal
return `PayPal (${method.email})`;
}
// Here, method has type CreditCard
return `Credit card (${method.cardNumber})`;
}
// Type (message: string) => never
const failwith = (message: string) => {
throw new Error(message);
};
TypeScript 推断出 never 类型,因为该函数既没有返回类型注释,也没有可到达的端点(由控制流分析决定)。
不可能有该类型的变量
另一种情况是,never 类型被推断为从不为 ture。在下面的示例中,我们检查 value 参数是否同时是字符串和数字,这是不可能的。
function impossibleTypeGuard(value: any) {
if (
typeof value === "string" &&
typeof value === "number"
) {
value; // Type never
}
}
这个例子显然是过于作,来看一个更实际的用例。下面的示例展示了 TypeScript 的控制流分析缩小了类型守卫下变量的联合类型。直观地说,类型检查器知道,一旦咱们检查了 value 是字符串,它就不能是数字,反之亦然
function controlFlowAnalysisWithNever(
value: string | number
) {
if (typeof value === "string") {
value; // Type string
} else if (typeof value === "number") {
value; // Type number
} else {
value; // Type never
}
}
注意,在最后一个 else 分支中,value 既不能是字符串,也不能是数字。在这种情况下,TypeScript 推断出 never 类型,因为咱们已经将 value 参数注解为类型为 string | number,也就是说,除了string 或 number, value 参数不可能有其他类型。
一旦控制流分析排除了 string 和 number 作为 value 类型的候选项,类型检查器就推断出never 类型,这是惟一剩下的可能性。但是,咱们也就不能对 value 做任何有用的事情,因为它的类型是 never,所以咱们的编辑器工具不会显示自动显示提示该值有哪些方法或者属性可用。
never 和 void 之间的区别
你可能会问,为什么 TypeScript 已经有一个 void 类型为啥还需要 never 类型。虽然这两者看起来很相似,但它们是两个不同的概念:
阿里云最近在做活动,低至2折,真心觉得很划算了,可以点击本条内容或者链接进行参与:
https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
腾讯云最近在做活动,百款云产品低至 1 折,可以点击本条内容或者链接进行参与
TypeScript 2.0 实现了一个相当有用的功能:标记联合类型,您可能将其称为
sum 类型
或与其他编程语言区别开的联合类型。 标记联合类型是其成员类型都定义了字面量类型的区分属性的联合类型。上面的讲的是理论性的,来几个例子看看更贴切。
使用标记的联合类型构建付款方式
假设咱们为系统用户可以选择的以下支付方式建模
对于这些支付方法,咱们可以创建一个 TypeScript 接口
注意,除了必需的信息外,每种类型都有一个
kind
属性,即所谓的判别属性。这里每种情况都是字符串字面量类型。现在定义一个
PaymentMethod
类型,它是我们刚才定义的三种类型的并集。通过这种方式,用声明PaymentMethod
每个变量, 必须具有给定的三种组成类型中的一种:现在我们的类型已经就绪,来编写一个函数来接受付款方法并返回一个读得懂的话语:
首先,该函数包含的类型注释很少,
method
参数仅包含一个。除此之外,函数基本是纯 ES2015 代码。在
switch
语句的每个case
中,TypeScript 编译器将联合类型缩小到它的一个成员类型。例如,当匹配到"paypal"
,method
参数的类型从PaymentMethod
缩小到PayPal
。因此,咱们可以访问email
属性,而不必添加类型断言。本质上,编译器跟踪程序控制流以缩小标记联合类型。除了
switch
语句之外,它还要考虑条件以及赋值和返回的影响。控制流的类型分析 使得使用标记联合类型非常顺利。使用最少的 TypeScript 语法开销,咱可以编写几乎纯 JS,并且仍然可以从类型检查和代码完成中受益。
使用标记联合类型构建 Redux 操作
标记联合类型真正发挥作用的用例是在 TypeScript 应用程序中使用
Redux
时。 编写一个事例,其中包括一个模型,两个actions
和一个 Todo 应用程序的reducer
。以下是一个简化的
Todo
类型,它表示单个todo
。这里使用readonly
修饰符为了防止属性被修改。用户可以添加新的 todos 并切换现有 todos 的完成状态。根据这些需求,咱们需要两个
Redux
操作,如下所示:与前面的示例一样,现在可以将
Redux
操作构建为应用程序支持的所有操作的联合在本例中,
type
属性充当判别属性,并遵循Redux
中常见的命名模式。现在添加一个与这两个action
一起工作的Reducer
:同样,只有函数签名包含类型注释。代码的其余部分是纯 ES2015,而不是特定于 TypeScript。
我们遵循与前面示例相同的逻辑。基于
Redux
操作的type
属性,我们在不修改现有状态的情况下计算新状态。在switch
语句的情况下,我们可以访问特定于每个操作类型的text
和index
属性,而不需要任何类型断言。never 类型
TypeScript 2.0
引入了一个新原始类型never
。never
类型表示值的类型从不出现。具体而言,never
是永不返回函数的返回类型,也是变量在类型保护中永不为true
的类型。这些是
never
类型的确切特征,如下所述:never
是所有类型的子类型并且可以赋值给所有类型。never
的子类型或能赋值给never
(never
类型本身除外)。return
语句,或者只有never
类型表达式的return
语句,并且如果函数是不可执行到终点的(例如通过控制流分析决定的),则推断函数的返回类型是never
。never
返回类型注解的函数中,所有return
语句(如果有的话)必须有never
类型的表达式并且函数的终点必须是不可执行的。听得云里雾里的,接下来,用几个例子来讲讲
never
这位大哥。永不返回的函数
下面是一个永不返回的函数示例:
该函数由一个不包含
break
或return
语句的无限循环组成,所以无法跳出循环。因此,推断函数的返回类型是never
。类似地,下面函数的返回类型被推断为
never
TypeScript 推断出
never
类型,因为该函数既没有返回类型注释,也没有可到达的端点(由控制流分析决定)。不可能有该类型的变量
另一种情况是,
never
类型被推断为从不为ture
。在下面的示例中,我们检查value
参数是否同时是字符串和数字,这是不可能的。这个例子显然是过于作,来看一个更实际的用例。下面的示例展示了 TypeScript 的控制流分析缩小了类型守卫下变量的联合类型。直观地说,类型检查器知道,一旦咱们检查了
value
是字符串,它就不能是数字,反之亦然注意,在最后一个
else
分支中,value
既不能是字符串,也不能是数字。在这种情况下,TypeScript 推断出never
类型,因为咱们已经将value
参数注解为类型为string | number
,也就是说,除了string
或number
,value
参数不可能有其他类型。一旦控制流分析排除了
string
和number
作为value
类型的候选项,类型检查器就推断出never
类型,这是惟一剩下的可能性。但是,咱们也就不能对value
做任何有用的事情,因为它的类型是never
,所以咱们的编辑器工具不会显示自动显示提示该值有哪些方法或者属性可用。never 和 void 之间的区别
你可能会问,为什么 TypeScript 已经有一个
void
类型为啥还需要never
类型。虽然这两者看起来很相似,但它们是两个不同的概念:没有显式返回值的函数将隐式返回
undefined
。虽然我们通常会说这样的函数“不返回任何东西”,但它会返回。在这些情况下,我们通常忽略返回值。这样的函数在 TypeScript 中被推断为有一个void
返回类型。具有
never
返回类型的函数永不返回。它也不返回undefined
。该函数没有正常的完成,这意味着它会抛出一个错误,或者根本不会完成运行。函数声明的类型推断
关于函数声明的返回类型推断有一个小问题。咱们前面列出的几条
never
特征,你会发现下面这句话:它提到了函数表达式和箭头函数,但没有提到函数声明。也就是说,为函数表达式推断的返回类型可能与为函数声明推断的返回类型不同:
这种行为的原因是向后兼容性,如下所述。如果希望函数声明的返回类型
never
,则可以对其进行显式注释:代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:
https://mariusschulz.com/blog/tagged-union-types-in-typescript
https://mariusschulz.com/blog/the-never-type-in-typescript
交流
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
因为篇幅的限制,今天的分享只到这里。如果大家想了解更多的内容的话,可以去扫一扫每篇文章最下面的二维码,然后关注咱们的微信公众号,了解更多的资讯和有价值的内容。
每次整理文章,一般都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励
The text was updated successfully, but these errors were encountered: