TS学习-泛型基础

发布于:2024-05-02 ⋅ 阅读:(162) ⋅ 点赞:(0)

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);

以上。


网站公告

今日签到

点亮在社区的每一天
去签到