typescript泛型的用途(typescript类型详解)

 分类:前端开发时间:2023-07-27 07:30:06点击:

从自定义一个数据结构————栈(Stack)的例子解释什么是泛型? 为什么需要泛型?

栈是一种数据结构,读写上遵循先进后出原则(FILO, First In Last Out)。很简单,就像往一个纸箱里面不断地放a4纸(什么纸并不重要...), 最先放进去的在最底下,最后放进去的在最上面,因此之后拿的时候第一个拿到的是最后一个放进去的.

windows画图随手画的

下面用TypeScript实现一个栈,一枚合格的栈应该至少具备以下功能

  • 入栈

  • 出栈

  • 判断是否为空

  • 查看栈顶元素

  • 返回栈的深度

  • 清空栈

TypeScript 代码实现

interface Stack {
    isEmpty: () => boolean, // 判断是否为空
    peek: () => number,     // 返回栈顶元素
    pop: () => number,      // 弹出栈顶元素
    push: (item: number) => void,   // 入栈
    clear: () => void       // 清空栈
    size: () => number      // 返回栈的深度
}

class MyStack implements Stack {

    private data: number[];

    constructor() {
        this.data = [];
    }

    public isEmpty(): boolean {
        return this.data.length === 0;
    }

    public peek(): number {
        return this.data[this.data.length - 1]
    }

    public pop(): number {
        return this.data.splice(this.data.length - 1, 1)[0];
    }

    public push(item: number): void {
        this.data.push(item);
    }

    public clear(): void {
        this.data = [] as number[];
    }

    public size(): number {
        return this.data.length;
    }

}

测试一下

let myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.push(3);
myStack.push(4);
console.log(myStack.size())
console.log(myStack.peek())
console.log(myStack.pop())
console.log(myStack.size())
myStack.clear()
console.log(myStack.size())
console.log(myStack.isEmpty())
myStack.push(5)
console.log(myStack.isEmpty())

控制台结果

4
4
4
3
0
true
false

这样一个栈结构就完成了,但是现在这个栈有个严重的局限性,就是它只能存放number类型的元素,所有的操作也都是服务于number类型的,如果应用到实际项目中,难道要为每种类型都创建一个NumberStack, StringStack吗?

加入泛型

使用泛型可以大大增强扩展性,可以让我们定义的栈真正发挥作用

interface Stack<T> {
    isEmpty: () => boolean,
    peek: () => T,
    pop: () => T,
    push: (item: T) => void,
    clear: () => void
    size: () => number
}

class MyStack<T> implements Stack<T> {

    private data: T[];

    constructor() {
        this.data = [];
    }

    public isEmpty(): boolean {
        return this.data.length === 0;
    }

    public peek(): T {
        return this.data[this.data.length - 1]
    }

    public pop(): T {
        return this.data.splice(this.data.length - 1, 1)[0];
    }

    public push(item: T): void {
        this.data.push(item);
    }

    public clear(): void {
        this.data = [] as T[];
    }

    public size(): number {
        return this.data.length;
    }

}

观察以上代码,和之前number版的栈唯一的区别就是把,具象的number改成了抽象的T, 现在这里的T可以接受任何类型,包括我们自己在业务中的自定义类型

在每个函数体内,所有操作都围绕这个T类型, 泛型只要传入一个任意字母都可以, 大写小写都可以,只是一般业务开发中,大家有个约定俗成就行,也便于其他人阅读我们的代码

使用上就需要传入具体的类

let myStack = new MyStack<string>();
myStack.push('a');
myStack.push('b');
myStack.push('c');
myStack.push('d');
console.log(myStack.size())
console.log(myStack.peek())
console.log(myStack.pop())
console.log(myStack.size())
myStack.clear()
console.log(myStack.size())
console.log(myStack.isEmpty())
myStack.push('e')
console.log(myStack.isEmpty())

控制台

4
d
d
3
0
true
false
除注明外的文章,均为来源:老汤博客,转载请保留本文地址!
原文地址: