TS泛型详解 (超详细)

96 阅读1分钟

一. 什么叫泛型?

在函数定义时, 不确定参数是什么类型, 使用泛型后, 在函数调用时指定类型

//  <T>     定义泛型
// val: T   使用泛型
function getVal<T>(val: T): T {
  return val
}

getVal<string>('123')

二. 泛型约束

使用泛型后, 在函数未调用时, 函数本身并不知道即将传入的是什么类型, 所以在函数内部使用使用了泛型的参数时, 无法直接使用对应类型的方法或属性 (如图)

image.png

解决方案:

  • 1.使用条件语句进行类型收缩(书写较麻烦)
    function getVal3<T>(val: T) {
      if(typeof val === 'string') {
        console.log(val.length)
      }
      return val
    }
    getVal3('123456')
    
  • 2.添加约束 利用接口
    interface ILength {
      length: number
    }
    // (Type extends 接口)  添加泛型约束
    // 表示传入的类型必须满足 ILength 接口的要求
    function getVal4<T extends ILength>(val: T) {
      console.log(val.length)
      return val
    }
    getVal4('123456')
    

三. 多个泛型 与 keyof

现有需求 定义一个函数, 传入一个对象 和 一个字符串属性名, 返回属性值, 但是ts不确定能不能在obj对象中找到name属性, 就会报错 (如图)

image.png

keyof 关键字: 限制必须是某个对象的属性

解决方法:

// K extends keyof O  表示必须是 O 的属性
function getProp1<O, K extends keyof O>(obj: O, key: K) {
  return obj[key]
}
getProp1({name: '小丽'}, 'name')

当传入字符串不是obj对象属性的时候就会报错 (如图):

image.png

keyof 其他用法

type Person = {
  name: string,
  age: number,
  hobby: string
}
let p1: keyof Person = 'age' //表示只能是Person中的属性

四. 泛型接口

可以在接口中使用泛型, Array<string> 使用的就是泛型接口

interface Students<T> {
  id: number
  name: T
  hobby: T[]
}

let stu:Students<string> = {
  id: 1,
  name: '小美',
  hobby: [
    '篮球',
    '音乐'
  ]
}
console.log(stu)