面试官:说说你对 TypeScript 中高级类型的理解?有哪些?

开发 前端
除了string、number、boolean 这种基础类型外,在 typescript 类型声明中还存在一些高级的类型应用。

[[422806]]

本文转载自微信公众号「JS每日一题」,作者 灰灰。转载本文请联系JS每日一题公众号。

一、是什么

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

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

二、有哪些

常见的高级类型有如下:

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

交叉类型

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

语法如下:

  1. T & U 

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

  1. function extend<T , U>(first: T, second: U) : T & U { 
  2.     let result: <T & U> = {} 
  3.     for (let key in first) { 
  4.         result[key] = first[key
  5.     } 
  6.     for (let key in second) { 
  7.         if(!result.hasOwnProperty(key)) { 
  8.             result[key] = second[key
  9.         } 
  10.     } 
  11.     return result 

联合类型

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

语法如下:

  1. T | U 

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

如下所示:

  1. function formatCommandline(command: string[] | string) { 
  2.   let line = ''
  3.   if (typeof command === 'string') { 
  4.     line = command.trim(); 
  5.   } else { 
  6.     line = command.join(' ').trim(); 
  7.   } 

类型别名

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

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

  1. type some = boolean | string 
  2.  
  3. const b: some = true // ok 
  4. const c: some = 'hello' // ok 
  5. const d: some = 123 // 不能将类型“123”分配给类型“some” 

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

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

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

  1. type Tree<T> = { 
  2.     value: T; 
  3.     left: Tree<T>; 
  4.     right: Tree<T>; 

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

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

类型索引

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

  1. interface Button { 
  2.     type: string 
  3.     text: string 
  4.  
  5. type ButtonKeys = keyof Button 
  6. // 等效于 
  7. type ButtonKeys = "type" | "text" 

类型约束

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

  1. type BaseType = string | number | boolean 
  2.  
  3. // 这里表示 copy 的参数 
  4. // 只能是字符串、数字、布尔这几种基础类型 
  5. function copy<T extends BaseType>(arg: T): T { 
  6.   return arg 

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

  1. function getValue<T, K extends keyof T>(obj: T, key: K) { 
  2.   return obj[key
  3.  
  4. const obj = { a: 1 } 
  5. const a = getValue(obj, 'a'

映射类型

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

  1. type Readonly<T> = { 
  2.     readonly [P in keyof T]: T[P]; 
  3. }; 
  4.  
  5. interface Obj { 
  6.   a: string 
  7.   b: string 
  8.  
  9. type ReadOnlyObj = Readonly<Obj> 

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

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

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

  1. interface ReadOnlyObj { 
  2.     readonly a: string; 
  3.     readonly b: string; 

条件类型

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

  1. T extends U ? X : Y 

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

三、总结

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

参考文献

https://www.tslang.cn/docs/handbook/advanced-types.html

https://juejin.cn/post/6844904003604578312

 

https://zhuanlan.zhihu.com/p/103846208

 

责任编辑:武晓燕 来源: JS每日一题
相关推荐

2021-09-27 06:50:04

非线性数据

2021-09-26 10:57:16

集合操作场景

2021-08-09 07:47:40

Git面试版本

2021-11-25 10:18:42

RESTfulJava互联网

2021-08-20 08:33:19

操作系统OS

2021-09-06 10:51:27

TypeScriptJavaScript

2020-12-01 08:47:36

Java异常开发

2020-06-12 15:50:56

options前端服务器

2021-09-08 07:49:34

TypeScript 泛型场景

2021-09-10 06:50:03

TypeScript装饰器应用

2021-09-07 08:33:27

JavaScript TypeScript 函数

2021-09-16 07:52:18

算法应用场景

2019-05-10 10:50:04

Spring AOPJDK动态代理CGLIB动态代理

2021-11-02 22:04:58

模式

2022-02-21 17:24:18

序列化对象存储

2021-11-10 07:47:49

组合模式场景

2021-11-03 14:10:28

工厂模式场景

2021-08-16 08:33:26

git

2020-12-04 06:27:04

序列化面试官Java

2021-11-09 08:51:13

模式命令面试
点赞
收藏

51CTO技术栈公众号