typescript学习心得: 泛型<T>

177 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

泛型的作用

function echo(arg) {
    return arg
}
const result = echo('str')

这个时候 result 是一个 any 类型,any 类型在ts中是不推荐的。

一般ts有个类型推断, 比如: let test = 123, 这个时候 test 类型推断为一个 number。

但是类型推断无法推断函数里面的 arg,即类型推断无法流动到函数里面去推断。但是,我们仍然还想根据传入参数的不同,返回不同的类型。ts 所有的思想就是获得类型,如果没有获得类型,ts的威力就减少了90%以上。

所以,泛型是指在定义函数,接口或类的时候,不先预先指定具体的类型,而使用的时候再指定类型的一种特性

泛型使用

函数

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

使用:

let output = identity<string>('mystring')

还可以省略<string>, ts帮我们做了类型推论,推断T是字符串,推荐使用这种方式,这样代码比较精简。

let output1 = identity('string')

接口

interface generateFn { 
    <T>(arg: T): T 
}
// 还可以把参数类型T拿出来 
interface generateFn<T> { 
    (arg: T): T 
}

使用:

function identity<T>(arg: T): T { 
    return arg 
}
let myIn: generateFn = identity

class GenericNumber<T> {
    zeroNumber: T
    add(x: T, y: T) => T
}

let myGeneric = new GenericNumber<number>()
myGeneric.zeroNumber = 10
myGeneric.add = (x, y) => {
    return x + y
}

promise中的泛型

function withAPI(url: string) {
  return fetch(url).then(res => res.json())
}
withAPI('bai.com').then(res => {}) 

这个时候 res 是 any 类型,这不满足我们的要求,所以可以加上泛型。

interface BaiRes {
  name: string
  count: number
}
// Promise<T> 表示泛型在promise上传递
function withAPI<T>(url: string): Promise<T> {
  return fetch(url).then(res => res.json())
}
withAPI<BaiRes>('bai.com').then(res => {}) // 这个时候res就是BaiRes类型了

withAPI 函数返回一个 Promise,但是Promise返回的值没有类型,所以就加上了Promise<T>,这样函数传入的类型 BaiRes,就可以流入到Promise当中了,此时就可以看到 res 是一个 BaiRes 类型的对象。

再来看一个例子:

function loadImg(src: string) { 
  const promise = new Promise((resolve, reject) => {
      const img = document.createElement('img')
      img.onload = () => { 
          resolve(img)
      }
      img.onerror = () => { 
          reject('图片加载失败')
      }
      img.src = src
  })
  return promise
}

const result = loadImg(src)
result.then((img: HTMLImageElement) => {
  console.log('img.width', img.width)
  return img
})

此时,img: HTMLImageElement 这里会报错,这是因为promise返回的 img 的类型并不一定是HTMLImageElement 类型。

image.png

所以,需要给promise添加上泛型的类型 HTMLImageElement,这样类型 HTMLImageElement 就会流入到返回的值img上。

const promise = new Promise<HTMLImageElement>((resolve, reject) => {})

泛型约束

在函数体内,要访问参数的长度,但是并不是所有的参数都有length属性,比如数字。针对这种情况,就必须要对泛型进行约束,只能传具有length属性的参数。

interface Lengthwise {
    length: number
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length) 
    return arg
}

泛型K只能取obj里面的属性,不能获取之外的属性。

// 
function getProperty<T, K extends keyof T>(obj: T, key: K) {
    return obj[key]
}
let x = {a1b2c3}
getProperty(x, 'a')
getProperty(x, 'm'// 报错

keyof的作用,用来获取获取泛型T的key,比如下面的代码,Keys = name | area | population。

interface CountryResp {
  name: string
  area: number
  population: number
}

// keyof
type Keys = keyof CountryResp