返回顶部
首页 > 资讯 > 前端开发 > JavaScript >详解TypeScript2.0标记联合类型
  • 715
分享到

详解TypeScript2.0标记联合类型

2024-04-02 19:04:59 715人浏览 独家记忆
摘要

目录使用标记的联合类型构建付款方式使用标记联合类型构建 Redux 操作never 类型永不返回的函数不可能有该类型的变量never 和 void 之间的区别函数声明的类型推断使用标

使用标记的联合类型构建付款方式

假设咱们为系统用户可以选择的以下支付方式建模

  • Cash (现金)
  • PayPal 与给定的电子邮件地址
  • Credit card 带有给定卡号和安全

对于这些支付方法,咱们可以创建一个 typescript 接口


interface Cash {
  kind: "cash";
}

interface PayPal {
  kind: "paypal",
  email: string;
}

interface CreditCard {
  kind: "credit";
  cardNumber: string;
  securityCode: string;
}

注意,除了必需的信息外,每种类型都有一个kind属性,即所谓的判别属性。这里每种情况都是字符串字面量类型。

现在定义一个PaymentMethod类型,它是我们刚才定义的三种类型的并集。通过这种方式,用声明PaymentMethod每个变量, 必须具有给定的三种组成类型中的一种:


type PaymentMethod = Cash | PayPal | CreditCard;

现在我们的类型已经就绪,来编写一个函数来接受付款方法并返回一个读得懂的话语:


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})`;
  }
}

首先,该函数包含的类型注释很少,method参数仅包含一个。除此之外,函数基本是纯 ES2015代码。

在switch语句的每个case中,TypeScript 编译器将联合类型缩小到它的一个成员类型。例如,当匹配到"paypal",method参数的类型从PaymentMethod缩小到PayPal。因此,咱们可以访问email属性,而不必添加类型断言。

本质上,编译器跟踪程序控制流以缩小标记联合类型。除了switch语句之外,它还要考虑条件以及赋值和返回的影响。


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})`;
}

控制流的类型分析使得使用标记联合类型非常顺利。使用最少的 TypeScript语法开销,咱可以编写几乎纯js,并且仍然可以从类型检查和代码完成中受益。

使用标记联合类型构建 Redux 操作

标记联合类型真正发挥作用的用例是在 TypeScript 应用程序中使用Redux时。 编写一个事例,其中包括一个模型,两个actions和一个Todo应用程序的reducer。

以下是一个简化的Todo类型,它表示单个todo。这里使用readonly修饰符为了防止属性被修改。


interface Todo {
  readonly text: string;
  readonly done: boolean;
}

用户可以添加新的 todos 并切换现有 todos 的完成状态。根据这些需求,咱们需要两个Redux操作,如下所示:


interface AddTodo {
  type: "ADD_TODO";
  text: string;
}

interface ToggleTodo {
  type: "TOGGLE_TODO";
  index: number
}

与前面的示例一样,现在可以将Redux操作构建为应用程序支持的所有操作的联合


type ReduxAction = AddTodo | ToggleTodo;

在本例中,type属性充当判别属性,并遵循Redux中常见的命名模式。现在添加一个与这两个action一起工作的Reducer:


function todosReducer(
  state: ReadonlyArray<Todo> = [],
  action: ReduxAction
): ReadonlyArray<Todo> {
  switch (action.type) {
    case "ADD_TODO":
      // action has type AddTodo here
      return [...state, { text: action.text, done: false }];

    case "TOGGLE_TODO":
      // action has type ToggleTodo here
      return state.map((todo, index) => {
        if (index !== action.index) {
          return todo;
        }

        return {
          text: todo.text,
          done: !todo.done
        };
      });

    default:
      return state;
  }
}

同样,只有函数签名包含类型注释。代码的其余部分是纯 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这位大哥。

永不返回的函数

下面是一个永不返回的函数示例:


// Type () => never
const sing = function() {
  while (true) {
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
  }
}

该函数由一个不包含break或return语句的无限循环组成,所以无法跳出循环。因此,推断函数的返回类型是never。

类似地,下面函数的返回类型被推断为never


// 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类型。虽然这两者看起来很相似,但它们是两个不同的概念:

没有显式返回值的函数将隐式返回undefined。虽然我们通常会说这样的函数“不返回任何东西”,但它会返回。在这些情况下,我们通常忽略返回值。这样的函数在 TypeScript 中被推断为有一个void返回类型。

具有never返回类型的函数永不返回。它也不返回undefined。该函数没有正常的完成,这意味着它会抛出一个错误,或者根本不会完成运行。

函数声明的类型推断

关于函数声明的返回类型推断有一个小问题。咱们前面列出的几条never特征,你会发现下面这句话:

在函数表达式或箭头函数没有返回类型注解时,如果函数没有return语句,或者只有never类型表达式的return语句,并且如果函数是不可执行到终点的(例如通过控制流分析决定的),则推断函数的返回类型是never。

它提到了函数表达式和箭头函数,但没有提到函数声明。也就是说,为函数表达式推断的返回类型可能与为函数声明推断的返回类型不同:


// Return type: void
function failwith1(message: string) {
  throw new Error(message);
}

// Return type: never
const failwith2 = function(message: string) {
  throw new Error(message);
};

这种行为的原因是向后兼容性,如下所述。如果希望函数声明的返回类型never,则可以对其进行显式注释:


function failwith1(message: string): never {
  throw new Error(message);
}

以上就是详解TypeScript2.0标记联合类型的详细内容,更多关于TS2.0标记联合类型的资料请关注编程网其它相关文章!

--结束END--

本文标题: 详解TypeScript2.0标记联合类型

本文链接: https://lsjlt.com/news/125301.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 详解TypeScript2.0标记联合类型
    目录使用标记的联合类型构建付款方式使用标记联合类型构建 Redux 操作never 类型永不返回的函数不可能有该类型的变量never 和 void 之间的区别函数声明的类型推断使用标...
    99+
    2024-04-02
  • 【Python】类型注解 ⑤ ( Union 联合类型注解 | Union 联合类型语法 | 普通 / 容器 变量设置 Union 联合类型注解 | 函数设置 Unio&
    文章目录 一、Union 联合类型1、数据容器的类型注解问题2、Union 联合类型语法3、代码示例 - 普通变量设置 Union 联合类型注解4、代码示例 - ...
    99+
    2023-09-02
    python 开发语言 Union 联合类型 类型注解 原力计划
  • TypeScript联合类型,交叉类型和类型保护怎么理解
    本篇内容介绍了“TypeScript联合类型,交叉类型和类型保护怎么理解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.联合类型所谓的联合...
    99+
    2023-06-22
  • TypeScript联合类型,交叉类型和类型保护
    目录1.联合类型2.交叉类型3.类型保护3.1自定义类型保护3.2typeof 类型保护3.3instanceof类型保护1.联合类型 所谓的联合类型就是定义一些类型,定义的变量只...
    99+
    2024-04-02
  • TypeScript中的交叉类型和联合类型示例讲解
    目录交叉类型(Intersection types)要点联合类型(Union types)类型缩减 交叉类型(Intersection types) 什么事交叉类型呢?简单...
    99+
    2022-12-31
    TypeScript交叉类型与联合类型 TypeScript交叉类型 TypeScript联合类型
  • python的集合类型详解
    目录集合:创建集合集合的基本操作集合的内建函数和方法总结集合: 无序不重复的元素的组合 利用集合可以删除列表中的重复项(set()唱用作去重操作) 分类:可变集合(set),不可变...
    99+
    2024-04-02
  • 返回 Golang 中的联合类型
    Golang小白一枚,正在不断学习积累知识,现将学习到的知识记录一下,也是将我的所得分享给大家!而今天这篇文章《返回 Golang 中的联合类型》带大家来了解一下##content_title##,...
    99+
    2024-04-04
  • Python-typing: 类型标注与支持 Any类型详解
    Any docs Any 是一种特殊的类型。 静态类型检查器将所有类型视为与 Any 兼容,反之亦然, Any 也与所有类型相兼容。 这意味着可对类型为 Any 的值执行任何操作或方法调用,并将其赋值给任何变量: ...
    99+
    2022-06-02
    Python typing 类型标注 支持Any类型
  • TypeScript的交叉类型和联合类型是什么
    这篇文章主要介绍了TypeScript的交叉类型和联合类型是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇TypeScript的交叉类型和联合类型是什么文章都会有所收获,下面我们一起来看看吧。交叉类型(In...
    99+
    2023-07-04
  • Python组合数据类型详解
    目录集合元组创建方式列表操作函数操作方法 列表的引用字典查找修改和添加字典的操作函数字典的操作方法 集合 创建集合有两种方式: 第一种: T = {11,111,"11"}...
    99+
    2024-04-02
  • mybatis类型处理器JSR310标准详解
    目录类型处理器JSR310标准使Jackson和Mybatis支持JSR310标准类型处理器JSR310标准 首先什么是JSR310标准,其实就是新出的一些日期类型等的标准在,myb...
    99+
    2024-04-02
  • 在JavaScript中如何使用联合类型
    这篇文章将为大家详细讲解有关在JavaScript中如何使用联合类型,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。联合类型在 JavaScript 中,你希望属性为多种类...
    99+
    2024-04-02
  • Mybatis-Plus自定义集合类型的类型处理器详解
    目录1.配合xml文件2.手动注册两种方法,第一种很麻烦,对mp自带的插入操作有限制,后来改为更简洁的第二种方法 1.配合xml文件 TypeHandler @Slf4j @Map...
    99+
    2024-04-02
  • mysql联合索引详解
    比较简单的是单列索引(b+tree)。遇到多条件查询时,不可避免会使用到多列索引。联合索引又叫复合索引。 b+tree结构如下: 每一个磁盘块在mysql中是一个页,页大小是固定的,mysql innodb的默认的页大小是16k,每个索引会...
    99+
    2023-09-02
    mysql 数据库 sql
  • C语言自定义数据类型的结构体、枚举和联合详解
    结构体基础知识 首先结构体的出现是因为我们使用C语言的基本类型无法满足我们的需求,比如我们要描述一本书,就需要书名,作者,价格,出版社等等一系列的属性,无疑C语言的基本数据类型无法解...
    99+
    2024-04-02
  • C语言自定义类型详解(结构体、枚举、联合体和位段)
    目录前言一、结构体1、结构体类型的声明2、结构体的自引用3、结构体变量的定义和初始化4、结构体内存对齐5、结构体传参二、位段1、位段的定义 2、位段的内存分配3、位段的应用...
    99+
    2024-04-02
  • C语言关于自定义数据类型之枚举和联合体详解
    目录前言枚举枚举类型的定义枚举类型的优点枚举类型的使用枚举中需要注意的点联合体联合体类型的定义联合体的特点联合体的使用联合体存在内存对齐结语前言 在C语言的自定义数据类型中,除了我们...
    99+
    2024-04-02
  • PHP中标量类型、复合类型和特殊类型的示例分析
    这篇文章主要介绍了PHP中标量类型、复合类型和特殊类型的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在PHP中,支持8种原始数据类型,其中包括四种标量类型、两种复合...
    99+
    2023-06-20
  • C语言光标信息CONSOLE_CURSOR_INFO类型详解
    光标信息的结构体类型 typedef struct _CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; ...
    99+
    2024-04-02
  • Python的集合类型之set和frozenset详解
    目录集合类型—set,frozensetset和frozenset的实例提供以下操作:len(s)xinsxnotinsisdisjoint(other)issubset...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作