持续创作,加速成长!这是我参与「掘金日新计划 · 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 类型。
所以,需要给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 = {a: 1, b: 2, c: 3}
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