TypeScript | TS从入门到放弃系列之第二章“认识泛型”

80 阅读3分钟

人生没有错路,只有不同的感受

                 --Author:Tricia

泛型

泛型是可以在保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用 ,常用于:函数、接口、class 中

泛型函数

把类型当作参数来传递使用

  1. 语法:在函数名称的后面添加 <>(尖括号),尖括号中添加类型变量,比如此处的 Type
  2. 类型变量 Type,是一种特殊类型的变量,它处理类型而不是值
  3. 该类型变量相当于一个类型容器,能够捕获用户提供的类型(具体是什么类型由用户调用该函数时指定)
  4. 因为 Type 是类型,因此可以将其作为函数参数和返回值的类型,表示参数和返回值具有相同的类型
  5. 类型变量 Type,可以是任意合法的变量名称
<!---->

    function fn <T> (value : T) {
        return value
      }

      fn<number> (10)
      fn<string> ('haha')
      fn<boolean> (true)

案例

    // 1. 反转数组元素
      function reverseItem<T1, T2> (arr: [T1, T2]) : [T2, T1] {
        return [arr[1], arr[0]]
      }
      console.log(reverseItem(['haha',2]))
      console.log(reverseItem<string,boolean>(['haha',true]))

      // 2. 定义一个函数 参数1 是数字,参数2类型不固定, 返回的数组长度是参数1, 内容是参数2
      function getArr<T>(length: number, context: T) :T[] {
        let arr = []
        for(let i = 1; i <= length ; i++) {
          arr.push(context)
        }
        return arr
      }
      console.log(getArr<string>(5,'月'))

泛型约束

默认情况下,泛型函数的类型变量 Type 可以代表多个类型,这导致无法访问任何属性。此时,就需要为泛型添加约束来收缩类型(缩窄类型取值范围)

例如:

image.png

方法一: 指定更加具体的类型

  • 将类型修改为 Type[] (Type 类型的数组) ,因为只要是数组就一定存在 length 属性,因此就可以访问了
    function id<Type>(value: Type[]): Type[] {
        console.log(value.length)
        return value
      }
      
      id([1,2,3])

方法二:添加约束

    // 1. 创建一个接口
      interface ILength {
        length : number
      }
      function id2<Type extends ILength>(value: Type): Type {
        // 2. 继承接口:  表示传入的 类型 必须满足 ILength 接口的要求才行,也就是得有一个 number 类型的 length 属性
        console.log(value.length)
        return value
      }
      id2('hhhhh')
      id2([1,2,3])
      // id2(100) // 类型“number”的参数不能赋给类型“ILength”的参数

keyof关键字

keyof 关键字接收一个对象类型,生成其键名称(可能是字符串或数字)的联合类型

    interface IPeople {
        name: string
        age: number
        gender: string
        height: number
      }

      // keyof关键字 可以获取对象类型的键 并且将这些键联合成一个新类型
      type keyTypes = keyof IPeople
      let str: keyTypes = 'gender'

泛型接口

  1. 在接口名称的后面添加 <类型变量>,那么,这个接口就变成了泛型接口。
  2. 接口的类型变量,对接口中所有其他成员可见,也就是接口中所有成员都可以使用类型变量
  3. 使用泛型接口时,需要显式指定具体的类型

 interface IPeople<T> {
  name: T
  age: T
  height:T
  gender: T
  sayHi(song: T) : void
 }
 const p1: IPeople<string> = {
  name: 'Tricia',
  age: '十八',
  gender: '女',
  height: '一米八',
  sayHi(song) {
    console.log('我喜欢唱歌'+song)
  }
 }
 p1.sayHi('lala')

 const p2: IPeople<number> = {
  name: 11,
  age: 19,
  gender: 0,
  height: 180,
  sayHi(song) {
    console.log('我会唱'+song)
  }
 }
 p2.sayHi(78787)