目录
- 1,介绍
- 1,在函数中使用
- 2,在类型别名,接口中使用
- 3,在类中使用
- 2,泛型约束
- 3,多泛型
- 4,举例实现 Map
1,介绍
泛型相当于是一个类型变量,有时无法预先知道具体的类型,可以用泛型来代替。
通常会附属于函数,类,接口,类型别名之上。
举例:
在定义函数时,有时会丢失一些类型信息(多个位置应该保持一致)。
function handleArray(arr: any[], n: number): any[] {const temp: any[] = arr.slice(n)return temp
}handleArray([1,2,30], 2)
handleArray(['1', '2', '3'], 2)
当传递 number 类型数组时,上面代码中所有 any[]
都应该是 number[]
,string 数组同理。
用泛型来解决:
function handleArray<T>(arr: T[], n: number): T[] {const temp: T[] = arr.slice(n)return temp
}handleArray<number>([1,2,30], 2)
handleArray<string>(['1', '2', '3'], 2)
1,在函数中使用
使用方式:定义函数和调用函数时,都在函数名之后使用 < >
来定义泛型名称。
function handleArray<T>(arr: T[]): T[] {// ...
}handleArray<number>()
handleArray<string>()
泛型对函数来说:在调用函数时,告诉函数操作的具体类型,函数在执行时就能确定具体的类型。
特点:
1,只有在调用时,才能确定泛型的具体类型。
2,一般情况下,TS会智能的根据传递的参数,推导出泛型的具体类型。
以上面的例子来说,即便调用时没有写具体的泛型类型,函数也会根据传递的参数智能推导:
如果无法完成推导,并且没有传递具体的类型,默认为 unknown
。
function handleArray<T>(arr: any[], n: number): T[] {const temp: T[] = arr.slice(n)return temp
}// unknown[]
const res = handleArray([1,2,30], 2)
3,泛型也可以有默认值。
几乎用不到,因为泛型就是用来表示可能得任意类型。
function handleArray<T = number>(arr: T[]): T[] {// ...
}
2,在类型别名,接口中使用
看例子即可,实现一个 filter
函数。
// type callback = (n: number, i: number) => boolean;// type callback<T> = (n: T, i: number) => boolean;interface callback<T> {(n: T, i: number): boolean;
}function filter<T>(arr: T[], callback: callback<T>): T[] {let temp: T[] = [];arr.forEach((n, i) => {if (callback(n, i)) {temp.push(arr[i]);}});return temp;
}const res = filter([1, 2, 3, 4], (n, i) => n % 2 !== 0);
console.log(res);
3,在类中使用
类名上指定的泛型,可以传递到定义的属性和方法上。
type callback<T> = (item: T, index?: number, arr?: T[]) => boolean;class ArrayHelper<T> {constructor(private arr: T[]) {}myFilter(callback: callback<T>): T[] {let tempArr: T[] = [];this.arr.forEach((item, index, arr) => {if (callback(item, index, arr)) {tempArr.push(item);}});return tempArr;}
}const tempArr = new ArrayHelper([2, 3, 4, 5]);const res = tempArr.myFilter((item) => item % 2 === 0);console.log(res);
2,泛型约束
用于约束泛型的取值:必须得有类型约束(接口,类型别名)中的成员。
举例:泛型必须兼容 User
接口。
interface User {name: string;
}function updateName<T extends User>(obj: T): T {obj.name = obj.name.toUpperCase();return obj;
}const obj = {name: "lover",age: 19,
};const newNameObj = updateName(obj);
console.log(newNameObj);
3,多泛型
函数的参数会有多个,所以泛型也会有多个。
举例,混合2个不同类型的数组。
function mixinArray<T, K>(arr1: T[], arr2: K[]): (T | K)[] {const temp: (T | K)[] = [];for (let i = 0; i < arr1.length; i++) {temp.push(arr1[i]);temp.push(arr2[i]);}return temp;
}console.log(mixinArray([1, 2], ["11", "22"]));
4,举例实现 Map
这是 Map
的接口定义
interface Map<K, V> {clear(): void;/*** @returns true if an element in the Map existed and has been removed, or false if the element does not exist.*/delete(key: K): boolean;/*** Executes a provided function once per each key/value pair in the Map, in insertion order.*/forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;/*** Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.* @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.*/get(key: K): V | undefined;/*** @returns boolean indicating whether an element with the specified key exists or not.*/has(key: K): boolean;/*** Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.*/set(key: K, value: V): this;/*** @returns the number of elements in the Map.*/readonly size: number;
}
简单模拟实现:
class MyMap<K, V> {private keys: K[] = [];private values: V[] = [];get size() {return this.keys.length;}clear(): void {this.keys = [];this.values = [];}delete(key: K): boolean {const index = this.keys.indexOf(key);if (index !== -1) {this.keys.splice(index, 1);this.values.splice(index, 1);return true;} else {return false;}}forEach(callbackfn: (value: V, key: K, map: MyMap<K, V>) => void): void {this.keys.forEach((item, i) => {callbackfn(this.values[i], item, this);});}get(key: K): V | undefined {const index = this.keys.indexOf(key);return this.values[index];}has(key: K): boolean {return return this.keys.includes(key);}set(key: K, value: V): this {const index = this.keys.indexOf(key);if (index !== -1) {this.keys.push(key);this.values.push(value);} else {this.values[index] = value;}return this;}
}const myMap = new MyMap<string, number>();myMap.set("a", 1);
myMap.set("b", 2);
myMap.set("c", 3);
console.log(myMap.get("d"));
myMap.has("a");
console.log(myMap.delete("c"));myMap.forEach((value, key, self) => {console.log(value, key, self);
});myMap.clear();
console.log(myMap.size);
以上。