TS中的泛型
typescript 中 最难的无疑是泛型(Generices), 那么泛型出现的动机是什么呢?
思考一个问题: 泛型是怎样出现的,它要解决那些问题?
现在有一个 echo 方法,传入什么类型的值返回什么类型的值
function echo(arg) {
return arg
}
const result = echo(123)
result 返回值是一个 any 类型, 这不符合我们的预期, 那么指定入参和出参的类型,同样不符合预期, 这时候就用到泛型了
泛型(Generices)
定义
- 定义函数,接口或类时,不预先指定具体类型,而是在使用的时候指定具体类型
使用
- 在函数名称后面加一对尖括号,尖括号里面泛型名称(习惯写法为T,可以是任意名字),
- 泛型名称可以看成是一个变量(也可以看作是一个占位符)
- 泛型可以是任意类型在使用时指定即可
// 函数名后面插入尖括号,写入泛型名称T,参数和返回类型都是T
function echo<T>(arg:T):T {
return arg
}
const str: string = '字符串'
// result 是 string 类型
const result = echo(str)
// 也可以不指定类型, ts 可以自动推断出类型
const result = echo(123) // 此时 result 为 number 类型
现在有个元组,里面有两个不同类型的值, 把这个元组传入 swap 方法中, 交换两个值的位置, 返回交换位置后的元组
// 根据上面需求我们实现下
// 定义元组
const tuple:[number,string] = [123,'str']
// swap 方法实现
function swap<T,U>(tuple:[T,U]):[U,T] {
return [tuple[1],tuple[0]]
}
// 调用
const result = swap(tuple)
result[0]. 可以调用 字符串 的方法
result[1]. 可以调用 number 的方法
约束泛型
下面这个方法, 输出arg.length length下面有波浪线,出现了错误
下图提示: 泛型 T 不一定包含属性 length, 所以静态类型检查就会报错
那么这个函数接受的参数应该是有length属性的参数,使用 extends 关键字约束传入的泛型
使用 extends 使传入值满足约束条件
// 首先定义一个 IWithLength 的 interface
interface IWithLength {
length: number
}
// 在 泛型名称T后面 使用 extends 关键字继承定义的 IWithLength 接口
function echoWithLength<T extends IWithLength>(arg:T):T {
console.log(arg.length)
return arg
}
// 验证下
const str = echoWithLength(`str`)
const obj = echoWithLength({a:1,b:'str'})
const arr = echoWithLength([1,2,3])
使用泛型描述类
新建一个队列类上实现两个方法,进入队列,离开队列, 这时候就可以使用泛型类
// 类名称后面传入泛型
class Queue <T>{
private data:T[] = [];
push(item:T) {
return this.data.push(item)
}
pop():T {
this.data.shift()
}
}
// 实例化 的时候传入想要的类型
const queue1 = new Queue<number>()
queue1.push(1)
console.log(queue1.pop().toFixed()) // 这里返回类型就是number可以使用 number 方法
// 实例化 的时候传入想要的类型
const queue2 = new Queue<string>()
queue1.push(`str`)
console.log(queue2.pop().length) // 这时可以调用 string 的方法
使用泛型描述对象
// 定义类型的时候 动态指定值
interface KeyPair<T,U> {
key: T;
value: U;
}
let kp1: KeyPair<number,string> = { key: 123, value: 'str' }
let kp2: keypair<string,number> = { key: 'str', value: 123 }
使用泛型描述数组
定义一个number类型的数组
// 方法一
let arr2: Array<number> = [1,2,3]
// 方法二
interface Info {
age: number
name: string
}
let arr1: Info[] = [
{age: 18, name: 'lili'},
{age: 10, name: 'hihi'},
]
使用泛型描述函数
// 定义一个泛型接口
interface IPlus<T> {
(a:T,b:T) : T
}
// 变量绑定类型
const plus: Iplus<number> = function (a,b){
return a + b;
}
// number 类型
const a:Iplus<number> = plus(1,2)
// string 类型
const b:IPlus<string> = plus('hello','wold')