一、是什么

除了stringnumberboolean 这种基础类型外,在 typescript 类型声明中还存在一些高级的类型应用

这些高级类型,是typescript为了保证语言的灵活性,所使用的一些语言特性。这些特性有助于我们应对复杂多变的开发场景

二、有哪些

常见的高级类型有如下:

  • 交叉类型
  • 联合类型
  • 类型别名
  • 类型索引
  • 类型约束
  • 映射类型
  • 条件类型

交叉类型

通过 & 将多个类型合并为一个类型,包含了所需的所有类型的特性,本质上是一种并的操作

语法如下:

T & U

适用于对象合并场景,如下将声明一个函数,将两个对象合并成一个对象并返回:

function extend<T , U>(first: T, second: U) : T & U {
    let result: <T & U> = {}
    for (let key in first) {
        result[key] = first[key]
    }
    for (let key in second) {
        if(!result.hasOwnProperty(key)) {
            result[key] = second[key]
        }
    }
    return result
}

联合类型

联合类型的语法规则和逻辑 “或” 的符号一致,表示其类型为连接的多个类型中的任意一个,本质上是一个交的关系

语法如下:

T | U

例如 number | string | boolean 的类型只能是这三个的一种,不能共存

如下所示:

function formatCommandline(command: string[] | string) {
  let line = '';
  if (typeof command === 'string') {
    line = command.trim();
  } else {
    line = command.join(' ').trim();
  }
}

类型别名

类型别名会给一个类型起个新名字,类型别名有时和接口很像,但是可以作用于原始值、联合类型、元组以及其它任何你需要手写的类型

可以使用 type SomeName = someValidTypeAnnotation的语法来创建类型别名:

type some = boolean | string

const b: some = true // ok
const c: some = 'hello' // ok
const d: some = 123 // 不能将类型“123”分配给类型“some”

此外类型别名可以是泛型:

type Container<T> = { value: T };

也可以使用类型别名来在属性里引用自己:

type Tree<T> = {
    value: T;
    left: Tree<T>;
    right: Tree<T>;
}

可以看到,类型别名和接口使用十分相似,都可以描述一个对象或者函数

两者最大的区别在于,interface只能用于定义对象类型,而 type 的声明方式除了对象之外还可以定义交叉、联合、原始类型等,类型声明的方式适用范围显然更加广泛

类型索引

keyof 类似于 Object.keys ,用于获取一个接口中 Key 的联合类型。

interface Button {
    type: string
    text: string
}

type ButtonKeys = keyof Button
// 等效于
type ButtonKeys = "type" | "text"

类型约束

通过关键字 extend 进行约束,不同于在 class 后使用 extends 的继承作用,泛型内使用的主要作用是对泛型加以约束

type BaseType = string | number | boolean

// 这里表示 copy 的参数
// 只能是字符串、数字、布尔这几种基础类型
function copy<T extends BaseType>(arg: T): T {
  return arg
}

类型约束通常和类型索引一起使用,例如我们有一个方法专门用来获取对象的值,但是这个对象并不确定,我们就可以使用 extends 和 keyof 进行约束。

function getValue<T, K extends keyof T>(obj: T, key: K) {
  return obj[key]
}

const obj = { a: 1 }
const a = getValue(obj, 'a')

映射类型

通过 in 关键字做类型的映射,遍历已有接口的 key 或者是遍历联合类型,如下例子:

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

interface Obj {
  a: string
  b: string
}

type ReadOnlyObj = Readonly<Obj>

上述的结构,可以分成这些步骤:

  • keyof T:通过类型索引 keyof 的得到联合类型 'a' | 'b'
  • P in keyof T 等同于 p in 'a' | 'b',相当于执行了一次 forEach 的逻辑,遍历 'a' | 'b'

所以最终ReadOnlyObj的接口为下述:

interface ReadOnlyObj {
    readonly a: string;
    readonly b: string;
}

条件类型

条件类型的语法规则和三元表达式一致,经常用于一些类型不确定的情况。

T extends U ? X : Y

上面的意思就是,如果 T 是 U 的子集,就是类型 X,否则为类型 Y

三、总结

可以看到,如果只是掌握了 typeScript 的一些基础类型,可能很难游刃有余的去使用 typeScript,需要了解一些typescript的高阶用法,在实践场景中,还有更多更复杂的组合,需要在实践中慢慢体会

TypeScript 中高级类型的理解?有哪些?的更多相关文章

  1. C# vs TypeScript - 高级类型

    总目录 从C#到TypeScript - 类型 从C#到TypeScript - 高级类型 从C#到TypeScript - 变量 从C#到TypeScript - 接口 从C#到TypeScript ...

  2. 从C#到TypeScript - 高级类型

    C# vs TypeScript - 高级类型 上一篇讲了基础类型,基本上用基础类型足够开发了,不过如果要更高效的开发,还是要看下高级类型,这篇和C#共同点并不多,只是延用这个主题. 联合类型 可以从 ...

  3. 编写TypeScript工具类型,你需要知道的知识

    什么是工具类型 用 JavaScript 编写中大型程序是离不开 lodash 工具的,而用 TypeScript 编程同样离不开工具类型的帮助,工具类型就是类型版的 lodash .简单的来说,就是 ...

  4. TypeScript 条件类型精读与实践

    在大多数程序中,我们必须根据输入做出决策.TypeScript 也不例外,使用条件类型可以描述输入类型与输出类型之间的关系. 本文同步首发在个人博客中,欢迎订阅.交流. 用于条件判断时的 extend ...

  5. TypeScript 之类型判断

    在使用 Angular 做项目的时候,对 TypeScript 的类型判断不太熟练,为了方便查找,特意对 TypeScript 的类型判断做了简单梳理.文章只是 TS 官网的内容摘要,没有高深的知识, ...

  6. TypeScript的类型

    ⒈TypeScript的类型 JavaScript语言的数据类型包括以下7种: 1.boolean(布尔),true || false 2.null,表明null值得特殊关键字,JavaScript是 ...

  7. TypeScript入门三:TypeScript函数类型

    TypeScript函数类型 TypeScript函数的参数 TypeScript函数的this与箭头函数 TypeScript函数重载 一.TypeScript函数类型 在上一篇博客中已经对声明Ty ...

  8. React 与 Hooks 如何使用 TypeScript 书写类型?

    React 与 Hooks 如何使用 TypeScript 书写类型? 本文写于 2020 年 9 月 20 日 函数组件与 TS 对于 Hooks 来说是不支持使用 class 组件的. 如何在函数 ...

  9. typescript中类型断言好理解也好用

    类型断言是个好用的玩意,虽然typescript很强大,但是有时还不如我们知道一个值的类型,导致在开发过程中总是报一些令人头痛的类型错误.使用断言,简单来说就是先做好一个假设,使得编译通过. 我一开始 ...

随机推荐

  1. WordPress如何配置邮件发送?

    WordPress配置了邮件发送最直接的用处就是可以通过邮件找回密码,当然还有其他的用处,比如Wordpress有新用户注册,订单状态.评论等发生变化时给管理员发送邮件提醒等. 经过大量用户实践反馈, ...

  2. C++ //继承中构造和析构顺序

    1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Base 6 { 7 pu ...

  3. SpringBoot 如何进行参数校验,老鸟们都这么玩的!

    大家好,我是飘渺. 前几天写了一篇 SpringBoot如何统一后端返回格式?老鸟们都是这样玩的! 阅读效果还不错,而且被很多号主都转载过,今天我们继续第二篇,来聊聊在SprinBoot中如何集成参数 ...

  4. JAVA 调用第三方短信平台接口发送短信

    做了几个调用三方短信平台发送短信的例子,大部分需要 携带参数,向指定URL发送请求 回顾对接第一个平台时痛苦的乱码经历,这里放一份代码,算是个模版,再用到的时候过来copy一下就OK. 在进入主题之前 ...

  5. SpringMVC学习05(整合ssm)

    5.整合SSM 环境要求 环境: IDEA MySQL 5.7.19 Tomcat 9 Maven 3.6 要求: 需要熟练掌握MySQL数据库,Spring,JavaWeb及MyBatis知识,简单 ...

  6. Java:导出Excel大批量数据的优化过程

    背景 团队目前在做一个用户数据看板(下面简称看板),基本覆盖用户的所有行为数据,并生成分析报表,用户行为由多个数据来源组成(餐饮.生活日用.充值消费.交通出行.通讯物流.交通出行.医疗保健.住房物业. ...

  7. SpringBoot开发二十二-统一处理异常

    需求介绍 首先服务端分为三层:表现层,业务层,数据层. 请求过来先到表现层,表现层调用业务层,然后业务层调用数据层. 那么数据层出现异常它会抛出异常,那异常肯定是抛给调用者也就是业务层,那么业务层会再 ...

  8. Django CBV装饰器 中间件 auth模块 CSRF跨站请求

    CBV添加装饰器 给CBV添加装饰器有三种方法,三种方法都需要导入模块: from django.utils.decorators import method_decorator 第一种直接在方法上面 ...

  9. 题解 block

    传送门 如果不想让next_permutation()自动忽略重复元素,可以在比较函数里加个rk之类的东西使它们不同(next_permutation()不用等于号) 关于第一问:貌似也是一个挺常见的 ...

  10. udphdr结构

    udphdr结构包含在/usr/src/linux/include/linux/udp.h 1 struct udphdr { 2 __u16 source; 3 __u16 dest; 4 __u1 ...