一文带你了解 TypeScript 泛型
什么是泛型
我们先来看看 ChatGPT 怎么说:
:::success 泛型就是 将类型进行传递,然后确保在使用的时候类型正确。:::
泛型优缺点
优点
-
类型安全:使用泛型可以让代码在编译时就发现类型错误,避免了运行时类型错误的发生。
-
代码复用:泛型可以将一些通用的代码封装成可复用的函数或类,避免了重复编写类似的代码。
-
可读性较好:使用泛型可以增强代码的可读性和可维护性,使代码更加易于理解和修改。
-
提高性能:泛型 代码在 TypeScript 中不需要进行额外的类型检查和类型转换,可以提高程序的运行效率。
缺点
-
学习曲线陡峭:与 Java 中一样,使用泛型需要掌握类型参数、泛型方法和通配符等概念,这可能会使初学者感到困惑。
-
约束较强:在 TypeScript 中,泛型的类型参数需要满足一定的约束条件,这可能会限制泛型的使用范围和灵活性。
-
限制了某些操作:与 Java 中类似,在 TypeScript 中使用泛型时,由于类型参数的不确定性,有些操作是不支持的,例如创建泛型数组、使用 instanceof 运算符等。
-
需要考虑类型擦除:与 Java 中类似,泛型在 TypeScript 中也是通过类型擦除实现的,这可能会影响一些泛型代码的实现和设计。
泛型格式
泛型 用 <>
符号标识泛型类型, 一般是 T 作为 泛型变量 。
-
下面代码中,我们定义一个 获取数据的方法
getData
,给它传入了 泛型变量 T, 参数类型也是 T, 返回值的类型也是 T
function getData<T>(data : T): T { return data }
-
调用函数:::success 它有两种调用方式:
-
直接调用,传入参数, 编译器会进行类型推理
-
传入指定类型,然后输入的参数必须和指定的类型一致,不然会报错
:::
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:"https://www.sadasd.com"} console.log(websiteInfo) // { id: 221241234, source: '爬虫', url: 'https://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
你也许感兴趣的:
- [译文]Java 和 Scala 的类型系统是不健全的
- 解密Java增强的泛型
- “再见了,TypeScript!”,Ruby on Rails 之父 DHH 也因“类型”遭劝退
- “TypeScript不值得!”前端框架Svelte作者宣布重构代码,反向迁移到JavaScript引争议
- 前端框架Svelte放弃TypeScript,回归JavaScript
- 我踩过了 TypeScript 的坑,只想告诉你快来
- 花了四年迁移到 TypeScript,我们总结出了这些经验教训
- Python之父是如何从TypeScript“抄”设计想法的
- 前端程序员需要知道的几个概念:ECMA5Script 、ECMAScript6、TypeScript
- 关于静态类型令人震惊的秘密
你对本文的反应是: