目录
- 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);
以上。