3

一文带你了解 TypeScript 泛型

 1 year ago
source link: https://www.techug.com/post/an-article-takes-you-to-understand-typescript-generics145159810564be882769/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client



an-article-takes-you-to-understand-typescript-generics145159810564be882769.01.jpeg
an-article-takes-you-to-understand-typescript-generics145159810564be882769.02.png

什么是泛型

我们先来看看 ChatGPT 怎么说:

:::success 泛型就是 将类型进行传递,然后确保在使用的时候类型正确。:::

泛型优缺点

  1. 类型安全:使用泛型可以让代码在编译时就发现类型错误,避免了运行时类型错误的发生。

  2. 代码复用:泛型可以将一些通用的代码封装成可复用的函数或类,避免了重复编写类似的代码。

  3. 可读性较好:使用泛型可以增强代码的可读性和可维护性,使代码更加易于理解和修改。

  4. 提高性能:泛型 代码在 TypeScript 中不需要进行额外的类型检查和类型转换,可以提高程序的运行效率。

  1. 学习曲线陡峭:与 Java 中一样,使用泛型需要掌握类型参数、泛型方法和通配符等概念,这可能会使初学者感到困惑。

  2. 约束较强:在 TypeScript 中,泛型的类型参数需要满足一定的约束条件,这可能会限制泛型的使用范围和灵活性。

  3. 限制了某些操作:与 Java 中类似,在 TypeScript 中使用泛型时,由于类型参数的不确定性,有些操作是不支持的,例如创建泛型数组、使用 instanceof 运算符等。

  4. 需要考虑类型擦除:与 Java 中类似,泛型在 TypeScript 中也是通过类型擦除实现的,这可能会影响一些泛型代码的实现和设计。

泛型 用 <> 符号标识泛型类型, 一般是 T 作为 泛型变量 。

  1. 下面代码中,我们定义一个 获取数据的方法 getData ,给它传入了 泛型变量 T, 参数类型也是 T, 返回值的类型也是 T

function getData<T>(data : T): T {
    return data
}

  1. 调用函数:::success 它有两种调用方式:

  2. 直接调用,传入参数, 编译器会进行类型推理

  3. 传入指定类型,然后输入的参数必须和指定的类型一致,不然会报错

type UserInfo =  {
    id:Number,
    name:String,
    address:String,
}




interface  EmailInfo {
    to:String,
    from:String,
    content:String,
    time:Date
}


function getData<T>(data : T): T {
    return data
}


console.log(getData("测试"))
// 测试


console.log(getData<UserInfo>({id:1,name:"海军",address:"上海"}))
// { id: 1, name: '海军', address: '上海' }


console.log(getData<EmailInfo>({to:'Amy',from:"John",content:"最近过的好吗",time: new Date()}))


// {
//     to: 'Amy',
//     from: 'John',
//     content: '最近过的好吗',
//     time: 2023-04-16T13:52:26.026Z
// }

:::success 泛型接口可以这样理解:当你需要给接口指定类型时,但目前不知道属性类型为什么时,就可以采用泛型接口你可以给接口指定参数为多个泛型类型,也可以单个;当使用时,明确参数类型即可。:::

interface GenericIdentityFn<T,S,D> {
    id: T,
    source:S,
    url: D
}
   


const websiteInfo : GenericIdentityFn<Number,String,String>  = {id:2212,source:"爬虫",url:"http://www.sadasd.com"}


console.log(websiteInfo)


// { id: 221241234, source: '爬虫', url: 'http://www.sadasd.com' }

什么是泛型类

它规定了类中属性和方法的 类型,而且必须和类型定义的类型保持一致。

泛型类的作用

可以帮助我们确认类的所有属性都在使用相同的类型

class 类名<T> {
 name!: T;
 hobby!: T;
}


# 这样这个类的所有类型为 number
let 实例 =  new 类名<number>();








class GenericityA<X>{
    sex!: X;
    age!: X;
}




let gen = new GenericityA<number>();


// gen.sex = '测试'   报错
gen.age = 3
console.log(gen.age)

通过定义接口, 泛型函数继承接口,则参数必须实现接口中的属性,这样就达到了泛型函数的约束。

# 第一种
// 定义接口
 interface DataInfo{
     title: string,
     price: number
 }




//  泛型函数 继承接口,进行对参数类型约束, 如果传入的参数中,没有包含接口属性,则编译不通过
 function getDataInfos< T extends DataInfo> (obj: T) : T {
     return obj
 }


 let book = {
     title: '前端进阶',
     price: 50,  
     author: '小新'
 }


 console.log(getDataInfos(book)) //{ title: '前端进阶', price: 50, author: '小新' }





通过给类的泛型指定为另一个类,这样就规定了类泛型的类型都为另一个类

# 第二种
//  通过类来约束
 class Login{
    username: string;
    password: string;
    constructor(username: string,password:string){
        this.username = username
        this.password = password
    }
 }


class Mysql<T>{
    login<T>(info:T):T{
        return info
    }
}


let  x = new Login('admin','12345');
let  mysql = new Mysql<Login>();
console.log(mysql.login(x)) //Login { username: 'admin', password: '12345' }

本文文字及图片出自 InfoQ


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK