typescript学习回顾(五)

今天来分享一下ts的泛型,最后来做一个练习

泛型

有时候,我们在书写某些函数的时候,会丢失一些类型信息,比如我下面有一个例子,我想提取一个数组的某个索引之前的所有数据

ts 复制代码
function getArraySomeData(newArr, n:number) {
    let newArr2:any[] = [];
    newArr.forEach((it, i) => {
        if (n > i) {
            newArr2.push(it);
        }
    });

    return newArr2;
}

const arr = getArraySomeData(['1112', '1213', '121'], 2);
console.log(arr)

但是这个数组它可以是任意类型的,可以是对象,字符串,数字数组,这个时候不约束的话会存在ts的隐患,这个时候就有了泛型的概念。

概念

泛型的一个概念:

泛型相当于是一个类型变量,在定义时,无法预先知道具体的类型,可以用该变量来代替,只有在调用时,才能确定它的类型

很多时候,TS会智能的根据传递的参数,推导出泛型的具体类型

我们可以把刚才的代码使用泛型改成这种形式

ts 复制代码
function getArraySomeData<T>(newArr:T[], n:number) {
    let newArr2:T[] = [];
    newArr.forEach((it, i) => {
        if (n > i) {
            newArr2.push(it);
        }
    });

    return newArr2;
}

const arr = getArraySomeData(['1112', '1213', '121'], 2);
console.log(arr)

如果没有传递具体类型,无法完成推导,默认是空对象。

进行传值

如果我 传递值只有ts会根据传递的类型进行严格类型检查,如下图,传递的是number,传递的就必须都是number

泛型设置默认值
function getArraySomeData<T = number>(newArr:any[], n:number) {

}
在类型别名、接口、类使用泛型

回调函数,判断数组的某一项是否满足条件,这个某一项可以用泛型来代替

类型别名

ts 复制代码
type callback<T> = (n:T,i:number) => boolean;

接口

下面手动写了一个筛选的filter函数

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

下面这个例子是一个数组帮助类,通过在类最外面设置了泛型T,来约束里面所有的方法的泛型,之后传递的所有的参数泛型以及数组放行,都是传递的值。

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 + min)
    }
}
泛型约束

这个是在有些特定场景的时候会需要使用,这里举一个简单的例子,我传递一个对象,然后我需要把这个对象的时间戳转换成日期字符串的形式

ts 复制代码
function dateFormat<T>(obj:T):T{
	obj.time = util.timeFormat(obj.time);
	return obj;
}

这个时候,ts会智能报错,报错的位置是obj.time的位置,因为泛型可以传递的类型是任意的类型,所以我用对象属性的方式,ts会进行报错,所以这种情况需要类型的约束

具体怎么做呢,很简单

ts 复制代码
interface hasTimePro{
	time : number
}

function dateFormat<T extends hasTimePro>(obj:T):T{
	obj.time = util.timeFormat(obj.time);
	return obj;
}

上面通过接口定义要约束的泛型的类型,可以是对象,也可以是其他。然后在泛型里进行继承,继承这个接口,这样就可以对这个泛型进行一个约束。

多泛型

在很多情况下,我们可能参数特别多,要限制的类和接口可能不止一个,所以ts同样支持可以有多个泛型,具体的使用例子

我希望混合两个 数组,数组1和数组2,两个可能都是不一样的数组,但是两个数组长度必须一样,至于传递什么类型不管,只负责混合。这里就可以通过英文逗号将泛型隔开,然后设置多个泛型

ts 复制代码
function mixinArray<T, K>(arr1: T[], arr2: K[]): (T | K)[] {
    if (arr1.length !== arr2.length) {
        throw new Error('两个数组长度不等');
    }
    let result: (T | K)[] = [];
    for (let i = 0; i < arr1.length; i++) {
        result.push(arr1[i]);
        result.push(arr2[i]);
    }

    return result;
}

const result = mixinArray([1, 3, 4], ["a", "b", "c"]);

result.forEach(r => console.log(r));
小练习
ts 复制代码
开发一个字典类(Dictionary),字典里会保存键值对的数据

键值对数据的特点:
- 键(key)可以是任何类型,但不允许重复
- 值(value)可以是任何类型
- 每一个键对应一个值
- 所有的键类型相同,所有的值类型相同

字典类对键值对数组的操作:

- 添加一个键值对
- 按照键删除对应的键值对
- 循环每一个键值对
- 得到当前键值对的数量
- 判断某个键是否存在
- 重新设置某个键的值,如果不存在,就添加
代码
  • src

    • dictionary.ts
    ts 复制代码
    export type CallBack<K, V> = (key: K, val: V) => void
    
    export class Dictonary<K, V> {
        private keys: K[] = [];
        private vals: V[] = [];
    
    
        get size() {
            return this.keys.length;
        }
    
        set(key: K, val: V) {
            const i = this.keys.indexOf(key)
            if (i < 0) {
                this.keys.push(key);
                this.vals.push(val);
            } else {
                this.vals[i] = val;
            }
        }
    
        forEach(callback: CallBack<K, V>) {
            this.keys.forEach((k, i) => {
                const v = this.vals[i];
                callback(k, v);
            });
        }
    
        has(key: K) {
            return this.keys.includes(key);
        }
    
        delete(key: K) {
            const i = this.keys.indexOf(key);
            if (i === -1) {
                return;
            }
            this.keys.splice(i, 1);
            this.vals.splice(i, 1);
        }
    }
    • index.ts
    ts 复制代码
    import { Dictonary } from "./dictionary";
    
    const dic = new Dictonary<string, number>();
    
    dic.set('a', 1);
    dic.set('b', 1);
    dic.set('a', 12);
    dic.set('c', 1231);
    
    dic.forEach((d,i)=>{
        console.log(`key:${d},v:${i}`)
    });
    
    dic.delete('b');
    
    dic.forEach((d,i)=>{
        console.log(`key:${d},v:${i}`)
    });
    
    console.log('当前键值对的数量:' + dic.size)
相关推荐
汤姆和佩琦5 分钟前
2024-12-25-sklearn学习(20)无监督学习-双聚类 料峭春风吹酒醒,微冷,山头斜照却相迎。
学习·聚类·sklearn
IT女孩儿8 分钟前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
好学近乎知o16 分钟前
正则表达式(学习Django过程中可能涉及的)
学习·正则表达式·django
雨中奔跑的小孩19 分钟前
爬虫学习案例8
爬虫·学习
jieshenai21 分钟前
使用 VSCode 学习与实践 LaTeX:从插件安装到排版技巧
ide·vscode·学习
灰太狼不爱写代码3 小时前
CUDA11.4版本的Pytorch下载
人工智能·pytorch·笔记·python·学习
@解忧杂货铺4 小时前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js
eybk9 小时前
Pytorch+Mumu模拟器+萤石摄像头实现对小孩学习的监控
学习
6.949 小时前
Scala学习记录 递归调用 练习
开发语言·学习·scala
真的很上进9 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html