一、泛型
泛型: 是指附属于类型、类、接口、类型别名之上的类型。
- 书写某个函数时,会丢失一些类型信息(多个位置的类型应该保持一致或有关联的信息)。
- 泛型相当于是一个类型变量,在定义时,无法预先知道具体的类型,可以用该变量来代替,只有到调用时,才能确定它的类型。
- 很多时候, TS 会智能的根据传递的参数,推导出泛型的具体类型。
- 如果无法完成推导,并且又没有传递具体的类型,默认为空对象。
- 泛型可以设置默认值。
1.在函数中使用泛型
在函数名之后写上 <泛型名称> :
为函数指定一个泛型,名称为 T ,调用函数时传递一个 number 类型,则 T 为 number 类型,可以作为函数参数、函数返回值、和函数里面数值类型使用。下方示例中,为 T 指定了默认类型为 number 。
ts
function take<T = number>(arr:T[],n:number): T[] {
if (n >= arr.length) {
return arr;
}
const newArr: T[] = []
for (let i = 0; i < n; i++) {
newArr.push(arr[i])
}
return newArr
}
const newArr = take<number>([1, 2, 3, 4, 5], 2)
console.log(newArr); // [ 1, 2 ]
2.在类型别名、接口和类中使用泛型
类型别名直接在名称后写上 <泛型名称> :
ts
type callback<T> = (n: T, i: number) => boolean
function filter<T>(arr: T[], callback: callback<T>): T[] {
const newArr: T[] = []
arr.forEach((n, i) => {
if (callback(n, i)) {
newArr.push(n)
}
})
return newArr
}
const arr = [3, 4, 5]
console.log(filter<number>(arr, n => n % 2 !== 0)); // [ 3, 5 ]
接口直接在名称后写上 <泛型名称> :
ts
interface callback<T> {
(n: T, i: number): boolean
}
function filter<T>(arr: T[], callback: callback<T>): T[] {
const newArr: T[] = []
arr.forEach((n, i) => {
if (callback(n, i)) {
newArr.push(n)
}
})
return newArr
}
const arr = [3, 4, 5]
console.log(filter<number>(arr, n=> n % 2 !== 0)); // [ 3, 5 ]
类直接在名称后写上 <泛型名称> :
ArrayHelper.ts :
ts
export class ArrayHelper<T> {
constructor(private arr: T[]) { }
take(n:number): T[] {
if (n >= this.arr.length) {
return this.arr;
}
const newArr: T[] = []
for (let i = 0; i < n; i++) {
newArr.push(this.arr[i])
}
return newArr
}
shuffle() {
for (let i = 0; i < this.arr.length; i++) {
const targetIndex = this.getRandom(0, this.arr.length)
const temp = this.arr[i]
this.arr[i] = this.arr[targetIndex]
this.arr[targetIndex] = temp
}
}
private getRandom(min: number, max: number) {
const dec = max - min
return Math.floor(Math.random() * dec + max)
}
}
index.ts :
由于 TS 自带的类型推导,所以 <泛型名称> 有时可以省略。
二、泛型约束
泛型约束: 用于限制泛型的取值。
在下方代码中定义一个接口,里面有一个属性 name 为字符串 类型,函数中使用继承了该接口属性的泛型作为函数的参数和返回值。 泛型约束满足鸭子辨型法。
ts
interface hasNameProperty {
name: string
}
const person = {
name: "rata li",
age: 18,
gender:"男"
}
/**
* 将某个对象的name属性的每个单词的首字母转换为大写,然后返回该对象
*/
function nameToUpperCase<T extends hasNameProperty>(obj:T): T {
obj.name = obj.name
.split(" ")
.map(i => i[0].toUpperCase() + i.substring(1))
.join(" ")
return obj
}
const newPerson = nameToUpperCase(person)
console.log(newO.name) // Rata Li
此时,参数中必须包含 name 属性,如果去掉对象 person 中的 name 属性,则会报错:
三、多泛型
多泛型:写一些函数或者类时,依赖多个类型的时候需要使用多泛型。
ts
/**
* 将两个数组进行混合,[1,3,4] ["a","b","c"] => [1,"a",2,"b",3,"c"]
*/
function mixinArray<T, K>(arr1: T[], arr2: K[]): (T | K)[] {
if (arr1.length !== arr2.length) {
throw new Error("两个数组长度不等")
}
let newArr: (T | K)[] = []
for (let i = 0; i < arr1.length; i++) {
newArr.push(arr1[i]);
newArr.push(arr2[i]);
}
return newArr
}
const arr = mixinArray([1, 2, 3], ["a", "b", "c"])
console.log(arr);