目录
- 介绍
- 开始
- 如何理解泛型语法
- 泛型约束
- 泛型默认值
- 练习
- 后续
介绍
泛型在typescript 中使用频率相当高,也给了初学者相当大的阻碍。希望这一篇文章,能帮助你们爆破它。
开始
下面通过模拟实现一个简易版本的axios来引入泛型的使用
// axios.ts
type Method =| 'get'| 'GET'| 'delete'| 'Delete'| 'head'| 'HEAD'| 'options'| 'OPTIONS'| 'post'| 'POST'| 'put'| 'PUT'| 'patch'| 'PATCH'interface AxiosRequestConfig {baseURL?: string //便于为 axios 实例的方法传递相对 URLurl?: string // 请求地址 /* 注 ? 表示可选 */method?: Method // 请求方法 可选data?: any // post、patch 等类型请求的数据 可选params?: any // post、patch 等类型请求的数据 可选headers?: anyresponseType?: XMLHttpRequestResponseType
}type AxiosResponse= {/*** 响应的data数据*/data: any/*** 响应的状态码*/status: number}type AxiosPromise = Promise<AxiosResponse>class Axios {default:AxiosRequestConfig={}constructor(initConfig: AxiosRequestConfig) {console.log('axios---init');}get(url: string, config?: AxiosRequestConfig): AxiosPromise{return new Promise((resolve)=>{resolve({data: {},status:200,})})}
}export const createInstance=(config: AxiosRequestConfig)=>{const instance = new Axios(config)return instance
}
用它来模拟请求
import {createInstance} from "./axios"const axios = createInstance({baseURL:'https://some-domain.com/api/'
})axios.get('user/list').then(res=>{const {data} = res
})
痛点:
这时候 我们使用data 里的数据 是没有代码提示的,因为现在data的类型就是any。
这肯定对于我们开发来说是不方便的!
预期:
对于不同的请求,返回的数据格式是不同的。希望每个请求开发者都能自己去定义接口的请求类型!
解决:
使用泛型就能完美解决这个痛点!
改造 :
type Method =| 'get'| 'GET'| 'delete'| 'Delete'| 'head'| 'HEAD'| 'options'| 'OPTIONS'| 'post'| 'POST'| 'put'| 'PUT'| 'patch'| 'PATCH'interface AxiosRequestConfig<T=unknown> {baseURL?: string //便于为 axios 实例的方法传递相对 URLurl?: string // 请求地址 /* 注 ? 表示可选 */method?: Method // 请求方法 可选data?: T // post、patch 等类型请求的数据 可选params?: any // post、patch 等类型请求的数据 可选headers?: anyresponseType?: XMLHttpRequestResponseType
}type AxiosResponse<T=unknown>= {/*** 响应的data数据*/data: T/*** 响应的状态码*/status: number}type AxiosPromise<T> = Promise<AxiosResponse<T>>class Axios {default:AxiosRequestConfig={}constructor(initConfig: AxiosRequestConfig) {console.log('axios---init');}get<T=unknown>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>{return new Promise((resolve)=>{resolve({//@ts-ignoredata: {},status:200,})})}
}export const createInstance=(config: AxiosRequestConfig)=>{const instance = new Axios(config)return instance
}
使用:
import {createInstance} from "./axios"const axios = createInstance({baseURL:'https://some-domain.com/api/'
})type UserType = {name:string,age:number
}axios.get<UserType>('user/list').then(res=>{const {data} = res
})
总结: 泛型是一种用于创建可复用的函数或类的技术,它允许你在编写代码时指定类型参数,以使函数或类适用于不同类型的数据。
如何理解泛型语法
function identity<T>(arg: T): T {return arg;
}
看到 语法会感到陌生。它没有什么特别,可以把它类比于函数的入参,你可以随意去定义它的参数名,但是一般ts规范使用 大写的英文字母。
例如:T 就是接受的类型 ,T可以在。只有在外部使用它时 ,T的类型才被确定!
function identity<T>(arg: T): T {let temp:T;let str = '123'str as Treturn arg;
}
也可以接受多个外部类型
function cross<T,K>(arg1: T,arg2:K): T&K {return {...arg1,...arg2};
}
泛型约束
想要限制外部传入类型必须带有 length 属性,可以使用关键字 extends
function loggingIdentity<T>(arg: T): T {console.log(arg.length);return arg;
}
改造后
外部传入的类型 必须带有length 属性 ,否则校验不通过
function loggingIdentity<T extends {length:number}>(arg: T): T {console.log(arg.length);return arg;
}loggingIdentity({a:12,length:22})
泛型默认值
泛型也支持给默认值
type arrType<T=string> = {list:Array<T>
}let obj:arrType ={list: ['2','3']
}let obj1:arrType<number> ={list: [1,2]
}
练习
实现一个函数 来通过属性值来获得对应的值
function getValueByKey(obj:any,key:string){return obj[key]
}let obj = {name:'kd',age:35
}let value = getValueByKey(obj,'name')
但是现在没有代码提示,需要使用泛型,一个代表传入对象的类型,一个代表传入key 的类型
function getValueByKey<T,K>(obj:T,key:K):T[K]{return obj[key]
}
因为 ts 不知道 T 和 K 的 关系 所以会报错,但是我们开发知道他们的关系 K 是 属于 T的 key值,于是我们给他们加上 类型限制!
function getValueByKey<T extends {[P:string]:any},K extends keyof T>(obj:T,key:K):T[K]{return obj[key]
}
keyof 关键字 后面再介绍, 它的作用是取 类型的 key 值的!
代码提示就出来了! 至于为啥使用的时候可以省略尖括号 是因为类型推断
这时候 T 代表 {name:string,age:number} K 代表 “name” | “age”
当然你也可以自己指定
function getValueByKey<T extends {[P:string]:any},K extends keyof T>(obj:T,key:K):T[K]{return obj[key]
}let obj = {name:'kd',age:35
}let value = getValueByKey<typeof obj, keyof typeof obj>(obj,'age')
后续
后面再会出一篇ts的高级篇,里面会涉及到更多的泛型的使用。