进来复习Ts<断言,类型守卫,泛型,模式匹配>

708 阅读6分钟
  • 不是TS保姆教程,而是针对几个知识点的详细复习

一、断言

🐳类型断言

  • 将一个联合类型断言为其中一个类型
    • ts不确定一个联合类型的变量到底是哪一个类型时,我们只能访问此联合类型的所有类型中共有的属性和方法
    • 当我们在还不确定类型的时候就需要访问其中一个类型特有的属性和方法,就需要将其断言指定为一个类型
    • 这种情况下类型时还不确定的,只是我们‘欺骗’了ts,使其相信我们指定的类型-并不代表运行时不会因此报错
  • 任何类型都可以被断言为anyany可以被断言为任何类型

🐳基础使用

  • <>尖括号写法
const anyValue: any = 'i am any now'
const lengths: number = (<string>anyValue).length
  • as写法
  • jsx语法中只支持这种写法,因此会更推荐这种写法
const anyValue: any = 'i am any now'
const lengths: number = (anyValue as string).length

🐳双重断言

  • 简单断言不是万能的,在一些情况下也会失效,例如无法直接把string强制断言为一个object类型的

image.png

  • 因此可以使用双重断言,先将类型断言为unknown或者any ,再接着断言为所需的类型从而实现双重断言
anyValue as unknown as object
anyValue as any as object

🐳非空断言

  • 用来断定变量一定不是nullundefined
  • !表示

image.png

let test: string | null | undefined
test!.toString()

🐳确定赋值断言

  • 解决变量在赋值前被使用的问题
let x!: number

二、类型守卫

  • 在语句的块级作用域 if语句或条目运算符表达式内 缩小变量类型的一种类型推断的行为
  • 帮助在块级作用域中获得更为需要的精准变量类型,从而减少不必要的类型断言
  • 主要的类型守卫有如下:
    • 类型判断: typeof
    • 属性判断: in
    • 实例判断:instanceof
    • 字面量相等判断:== , === ,!= ,!==

🐬typeof

  • 可以精细化数据类型进行操作
function typeofGuard(input: string | number | boolean) {
  if (typeof input == 'string') {
    //处理当传入参数类型为string时
  } else if (typeof input == 'number') {
     //处理当传入参数类型为number时
  } else if (typeof input == 'boolean') {
    //处理当传入参数类型为boolean时
  }
}

🐬instanceof

  • 通过构造函数细化类型的一种方式
  • 如果没有类型守卫的话直接实现某个类型特有属性会报错

image.png

class animal {
  name= 'string'
  type= 'string'
}
class person {
  name =  'string'
  age = 'number'
}
function instanceofGuard(input: animal | person) {
  if(input instanceof animal) {
    console.log(input.type);
  }
  if(input instanceof person) {
    console.log(input.age);
    
  }
}

🐬in

  • x in y : 表示x属性在y中存在
function checkObj(obj: T) { 
    if ("everyThing" in obj) { 
        //obj上存在everything这个属性
    } 
}

三、泛型

🐋泛型作用

  • 增强程序的可重用性,支持更多类型
  • 增强代码的可读性

🐋泛型语法

  • <>里写类型参数,一般可以用T来表示

🐋基本使用:处理单个函数参数

  • 输入输出一致,传入的为T类型,传出的也为T类型
function print<T>(arg: T):T {
    return arg
}
  • 使用时指定要使用的类型
print<string>('mouche')
  • 使用时让TS推断,自动推导出类型
print('mouche')

🐋基础使用:处理多个函数参数

function swiperItem<T, U>(item:[T, U]): [U, T] {
  return [item[1], item[0]]
}

🐋约束泛型

  • interface结合,以此约束类型
  • 因为直接用T的话,它是不确定T类型有没有length属性,因此会对此报错 image.png
  • 可以用T extends Ilength来解决
interface Ilength {
  length: number
}

function printLength<T extends Ilength>(args: T): T {
  console.log(args.length);
  return args
}

🐋泛型的运用:约束接口

  • 可以对interface进行改造,让interface更加灵活,使其属性的类型可以更加灵活
interface person<T ,U>{
  name: T,
  age: U
}
const test1: person<string, number> = { name: 'mouche', age:20}
const test2: person<number, string> = { name: 20, age:'mouche'}

🐋泛型的运用:定义数组

  • 这样的话可以有两个方式去定义数组
const numArr: number[] = [1,2,3]
const numArr1: Array<number> = [1,2,3]

🐋泛型的运用:定义函数的形状

  • 限制传入参数类型和传出参数类型
interface IFunc {
  <T>(length: number, value: T): Array<T>
}

const createArr: IFunc = function<T>(length: number, value: T): Array<T> {
  //do something
  return []
}

🐋泛型的运用:泛型类

  • 定义person里面的属性类型和方法
class person<T> {
  name: T
  add: (x: T ,y: T) => T
}
let myPerson = new person<string>();
myPerson.name = 'mouche',
myPerson.add = function(x, y) {
  return x + y
}

接下去来点不一样的

四、模式匹配

🐝模式匹配做提取

  • 通过extends对类型参数做匹配,结果保存到通过infer声明的局部类型变量里面,如果匹配就从该局部变量里拿到提取出的类型

  • infer:获取类型中的某个类型

    • 只能在条件类型的extends子句中使用
    • 得到的类型只能在true语句中使用
  • 关于 infer 的官方文档:Inferring Within Conditional Types

🐝数组类型

🐌取出数组类型的第一个元素的类型

  • 使用Arr extends unkown[]限制传入参数只能是一个数组,数组里的元素类型没有限制

    image.png

  • 将需要提取的第一个元素的类型放到通过infer声明的First变量,然后将其返回

    type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]]? First: never;
    
  • 使用如下:

    image.png

🐌取出数组类型的最后一个元素的类型

  • 这个与上面类似,一样是利用解构和infer
  • 将需要提取的最后一个元素元素的类型放到通过infer声明的Last变量,然后将其返回 image.png

🐌取去掉第一个元素的数组

  • 将需要提取的除去第一个元素的数组类型放到通过infer声明的rest变量,然后将其返回
    type shiftArr<Arr extends unknown[]> = Arr extends [unknown, ...infer rest]? rest: never;
    
  • 使用如下 image.png

🐌取去掉最后一个元素的数组

  • 将需要提取的除去最后一个元素的数组类型放到通过infer声明的rest变量,然后将其返回
    type PopArr<Arr extends unknown[]> = Arr extends [...infer rest, unknown]? rest: never;
    
  • 使用如下 image.png

🐝字符串

  • 字符串类型同样也是可以做模式匹配的

🦋 匹配前缀

  • 需要传入两个类型参数,一个为该字符串,一个为需要匹配的前缀
  • 让str去匹配一个模式类型,前面为需要匹配的前缀,后面为任意string
  • 匹配成功则返回true,失败则返回false
    type StartWith<str extends string, start extends string> = 
        str extends `${start}${string}`? true: false
    
    image.png

🦋替换匹配字符

  • 传入三个类型参数,分别为原始字符串str, 需要被匹配替换的字符串from,替换成的字符串to
  • 对传入的参数都限制为string
  • 用infer保存被匹配字段前的字符串段pre 和 被匹配字段后的字符串段 aft
  • return 用to替换from,加上infer保存的字符串段
    type RelplaceStr<str extends string , From extends string, to extends string> =
        str extends `${infer Pre}${From}${infer aft}` ? `${Pre}${to}${aft}` : str`
    
  • 使用如下 image.png

🐝函数

提取参数的类型

  • Func extends Function约束川润只能为函数
  • 参数类型通过infer保存到Args,然后对其进行返回
type GetParames<Func extends Function> = Func extends (...args: infer Args) => unknown ? Args: never