typescript的一些高级用法

67 阅读4分钟

is 关键字

TypeScript使用is关键字来实现类型保护 举一个简单的例子:

图片.png

此时的val提示的属性和方法是any

但如果给isNumbre这个方法加上is关键字,就可以起到类型保护的作用

图片.png

此时的val提示的属性和方法是number了。

keyof关键字

  • TypeScript 允许我们遍历某种类型的属性,并通过 keyof 操作符提取其属性的名称。
  • 该操作符可以用于获取某种 类型 的所有键,其返回类型是 联合类型,简单的说,它是作用于类型的,返回类型为联合类型。

1.作用 interfacetype

作用 interfacetype 类型时 keyof 将对象中的属性名都结构出来,并作为联合类型返回。

interface User {
  id: string
  name: string
  addr: string[]
}

type U1 = keyof User
// type U1 = 'id' | 'name'| 'addr'

2.作用于数组时

作用于数组时,将数组对应的属性全部作为联合类型返回。

type T1 = keyof []
// T1 = 'length' | 'concat' | 'splice' | ...

3. 作用于类时

作用于类时,将类生成的对象属性和方法,当联合类型返回。

4. 作用于any

直接看代码

type T1 = keyof any
// type T1 = 'string' | 'number' | 'symbol'

应用

typeof关键字

1. 获取对象的类型:

图片.png

2. 在枚举中使用

图片.png

3. 函数

function add(a: number, b:number) {
  return a + b
}
type AddType = typeof add

图片.png

图片.png

extends关键字

extends关键字,在不同的场景有不同的用法:

  • 表示继承/拓展的含义
  • 表示约束的含义
  • 表示分配的含义、

1. 继承

interface Pet {
  name: string
  age: number
}

interface Cat extends Pet {
  miao(): void
}
interface Dog extends Pet {
  wang(): void
}

const cat: Cat = {
  name: '悠米',
  age: 2,
  miao() {
    console.log(`喵喵`)
  }
}
const dog: Dog = {
  name: '旺财',
  age: 2,
  wang() {
    console.log(`汪汪`)
  }
}

2. 泛型约束

在书写泛型的时候,我们往往需要对类型参数作一定的限制,比如希望传入的参数都有 name 属性的数组我们可以这么写:

function sayHello<T extends {name: string}>(t: T) {
  console.log(`我是${t.name}`)
}
interface Student {
  name: string
  age: number
}
const stu1: Student = {
  name:'小明',
  age: 12
}
sayHello(stu1)

3. 条件分发

extends的第三种用法就是用来判断一个类型是不是可以分配给另一个类型,这在写高级类型的时候非常有用。

3.1 作为条件判断

interface Animal {
  name: string
}

interface Bird {
  name: string
  fly(): void
}
// 这里表示 T2类型是否可以分配给T1类型,根据类型提示是“YES”
type MyT = Bird extends Animal ? "YES" : "NO"

3.2 联合类型分配

比如有如下类型:

interface Fish {
  name:string
  type: '鱼'
}
interface Bird {
  name:string
  type: '鸟'
}
interface Swiming {
  swiming: string
}
interface Sky {
  sky: string
}

type MyType<T> = T extends Bird ? Sky : Swiming

然后给T传递一个联合类型,如下:

type IEnv = MyType<Fish | Bird>

那么:

type IEnv = Fish extends Bird ? Sky : Swiming | Bird extends Bird ? Sky : Swiming

所以:

type IEnv = Swiming | Sky

infer关键字

TypeScript中的infer具有推断类型变量的作用

来看一下内置ReturnType的实现:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

内置类型实现

Exclude

先来看用法,就是在一个类型中排除某些个类型

type MyType = Exclude<string | number | boolean, boolean>
// 此时 type MyType = string | number

思路:

type MyExclude = (string extends boolean ? never : string) |
( number extends boolean ? never : number) |
(boolean extends boolean ? never : boolean)

那么,Exclude的实现就是:

type MyExclude<T, U> = T extends U ? never : T

Extract

先来看用法,就是在一个类型中抽离某些个类型,跟Exclude相反

type T = Exclude<string | number | boolean, boolean>
// 此时 type MyExclude = boolean

实现

type MyExtract<T, U> = T extends U ? U : never

Pick

就是从一个复合类型中,取出几个想要的类型的组合,如下:

interface User {
  id: string
  name: string
  age: number
  addr: string[]
}
// 我只想要 id和name两个属性的类型,
type MyUser = Pick<User,'id' | 'name'>

图片.png

那么,如何实现该类型呢?

  1. 首先,要了解到TypeScript是如何遍历联合类型的。语法就是[P in T]:

图片.png

  1. TypeScript是如何根据类型的key获取类型的,语法就是T['key'],比如下面要获取User的id类型 图片.png

  2. 还有,Pick的第二个泛型参数需要进行类型约束,K extends keyof T

那么Pick的实现,就很简单了:

type MyPick<T, K extends keyof T> = {
  [P in K]: T[P]
}

Omit

Omit的作用和Pick相反,就是从一个复合类型中,剔除几个不想要的类型的组合,如下:

图片.png

既然和Pick相反,那么我们就是要从id | name | age | addr中剔除id | name。可以利用前面的Exclude:

type T1 = Exclude<keyof User, 'id'|'name'>
// type T1 =  age | addr

那么Omit的实现,就很简单了:

type MyOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

Record

用于属性映射:

interface PageInfo {
  title: string;
}

type Page = "home" | "about" | "contact";

const nav: Record<Page, PageInfo> = {
  about: { title: "about" },
  contact: { title: "contact" },
  home: { title: "home" },
};