typeScript中的泛型

259 阅读2分钟

主要阐述了:

  • 泛型与使用场景
  • 在函数、类、接口中如何使用泛型

为什么要使用泛型

许多时候,标注的具体类型并不能确定,比如一个函数的参数类型

function sort(items: Array<string>, order: 'desc'|'asc'): Array<string> {
    //...
}

上面的 sort 函数虽然标注了类型,但是同时也限制了传入的只能是字符串数组。实际上,我们是希望它能传入字符串数组、数字数组、甚至用户自定义的结构类型,这个时候我们希望传入的类型能在具体调用的时候再确定,就像是函数内部可变数据转为参数一样。泛型 - 就可以完成这个需求

泛型的使用

function sort<T>(items: T, order: 'desc'|'asc'): T {
    //...
}

所谓的泛型,就是给可变(不定)的类型定义变量(参数),<> 类似 ()

泛型接口

我们还可以在接口中使用泛型

场景 后端提供了一些接口,用以返回一些数据,依据返回的数据格式定义如下接口:

interface IResponseData {
    code: number;
    message?: string;
    data: any;
}

我们会发现该接口的 data 项的具体格式不确定,不同的接口会返回的数据是不一样的

// 用户接口
interface IResponseUserData {
    id: number;
    username: string;
    email: string;
}
// 文章接口
interface IResponseArticleData {
    id: number;
    title: string;
    author: IResponseUserData;
}

这个时候我们可以对 IResponseData 使用泛型

interface IResponseData<T> {
    code: number;
    message?: string;
    data: T;
}

下面是具体代码

function getUser<U>(url: string) {
    return fetch(url).then(res => {
        return res.json();
    }).then( (data: IResponseData<U>) => {
        return data;
    });
}
function getArticles<U>(url: string) {
    return fetch(url).then(res => {
        return res.json();
    }).then( (data: IResponseData<U>) => {
        return data;
    } )
}

~(async function(){
    let user = await getUser<IResponseUserData>('');
    if (user.code === 1) {
        console.log(user.message);
    } else {
        console.log(user.data.username);
    }

    let articles = await getArticles<IResponseArticleData>('');
    if (articles.code === 1) {
        console.log(articles.message);
    } else {
        console.log(articles.data.id);
        console.log(articles.data.author.username);
    }
});

泛型类

还可以这类中使用泛型

class Queue<T> {
    private items: Array<T> = [];

    add(item: T) {
        this.items.push(item);
    }

    remove(): T | undefined {
        return this.items.shift();
    }
}

let q1 = new Queue<string>();
q1.add('a');
q1.add('b');
let v = q1.remove();
if (v) {
    v.substring(0);
}

let q2 = new Queue<Element>();

let box = document.querySelector('.box');
let div = document.querySelector('div');
box && q2.add(box);
div && q2.add(div);
let v2 = q2.remove();
if (v2) {
    v2.classList.add('box')
}