这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战
总结一已经总结了差不多很多ts的东西啦
这个总结2主要讲泛型,虽然丸子对这一块还是有点模糊,但说一下自己的理解了
希望可以帮到大家
泛型介绍
软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
题外话,补充一下范型的历史
早在2001年8月,有一门基于Java,能运行在JVM上的编程语言,就实现过运行时泛型,它叫做Pizza。不过很可惜,Pizza在一年后就消亡了,主要的开发人员转入了Generic Java(简称GJ)项目中,而GJ这门语言的泛型整合了通配符之后,就构成了如今Java泛型的原型。
J2SE的开发者当然是明白Java泛型的问题的,在JVM LS 2015上,就有介绍几种泛型实现的比较:
C++使用编译时模板填充来实现泛型,对于每一种参数类型,都会产生一份代码,优势是能很好的指定各种类型,劣势是没有代码复用,会占用大量的空间。
C#则是把类型变量存入了二进制文件(以参数化二进制码的形式),这对于使用各种类型是有优势的,唯一存在的问题只是虚拟机的实现会复杂一些。
Java的泛型实现则是依赖擦除,这对于代码复用有好处,但是对于原始数据类型支持不足。
了解完泛型的历史,就不得不提一个人,Martin Odersky。此人是Pizza的作者,也是GJ的设计者之一,他在一次访谈中爆料:Java要支持泛型,遇到的最大的问题是向上兼容。
TypeScript 在设计的的时候就充分吸收了Java的范型设计思想。 就像C#和Java一样,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。
下面时候非范型的代码
/**
* x 只能是数字类型,如果需要接收任意类型的参数,那么需要使用any,或者函数重载
* @param x
*/
// function fn(x: number): number {
// return x * 10;
// }
// fn(10);
// fn('10');
下面我们展示一下范型的代码怎么写:
/**
* 泛型
* 很多时候,类型是写死的,这样就不利于复用
*
* 这样,我们就需要给类型这种值也可以设置变量
* <类型变量名>,一般系统使用单字母大写,比如 T,E...
* 写在函数名,参数列表之间,这是函数的
*/
// function fn<T>(x: T): number {
// return Number(x) * 10;
// }
//fn(1); //在调用fn函数的时候,同时给T赋值number
// fn<number>(1);
// fn<string>(1); //有问题的
// function fn(x) {
// return x * 10;
// }
// let a = fn(1);
// let b = fn(2);
// function fn(...args) {
// let arr: number[] = [];
// for (let i=0; i<args.length; i++) {
// arr[i] = args[i];
// }
// return arr;
// }
// let arr2 = fn('a', 'b', 'c');
// function fn<T, S>(arg1: T, arg2: S): [T,S]{
// return [arg1, arg2];
// }
// let a = fn<string, number>('a', 1);
// function fn<T>(arg: T[]): T[]{
// return arg;
// }
// fn<string>( ['1','2'] );
// fn<string>( [1,2] );
// let arr: number[] = [];
// let arr2: Array<number> = [];
对比后的代码解析:
我们给x添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。
我们把这个版本的x函数叫做泛型,因为它可以适用于多个类型。 不同于使用 any,它不会丢失信息,像第一个例子那像保持准确性,传入数值类型并返回数值类型。
泛型的类
TypeScript泛型类 - 把类作为参数类型的泛型类.
泛类:泛型可以帮助我们避免重复的代码以及对不特定数据类型的支持(类型校验),下面我们看看把类当做参数的泛型类: 先定义个类然后把类作为参数来约束数据传入的类型
class MyArray <T> {
private _data: T[] = [];
constructor() {
}
public mypush(v: T): number {
this._data.push(v);
return this._data.length;
}
}
// 对于arr对象这个实例来讲,里面的T就是string
let arr: MyArray<string> = new MyArray();
arr.mypush('1');
// 对于arr对象这个实例来讲,里面的T就是number
let arr2: MyArray<number> = new MyArray();
arr2.mypush(1);
// let a: Array<number> = [1,2,'1'];
上面的代码是使用MyArray类的一个范型展示。 这样的数组对象能够支持不同类型的的对象不用重新定义类。
只需要使用的时候,声明上类型,比如Array。
上面说了很多范型的内容,下面展示一下接口。
这个是接口和类的代码展示。
// // interface Person {
// // [attr: string]: any
// // }
// class Person {
// constructor(public username: string, public age: number) {
// }
// }
// // // // Person => 一个拥有Person类型对应特征的对象
// // let p1: Person = new Person('Kimoo', 30);
// // function SuperMan(obj: Person) {
// // obj.fly = function() {
// // console.log('fly');
// // }
// // }
// // function getPersonObj(constructor: Person) {// 我想约束传入的必须是一个构造函数
// // // Person 表示这个类型对应的对象,我们这里要的Person的构造函数,不是他的对象
// // // return new constructor();
// // return new constructor();
// // }
// // getPersonObj( Person );
// // function getArray(constructor: {new(): Array<string>}) { // {new()} 接收一个可以产生对象的构造函数
// // return new constructor();
// // }
// // getArray( Array );
// // Person类的对象
// // let a: Person;
// // let fn1: {new (): Person};
这里我们可以看到范型更像数据类型一样,接口跟类跟函数这些更多是一种结构的抽象。
范型就是一个*类型,可以随便传入一个类型。比如在使用一个接口的时候,加上类型。
但是跟any不同的是,范型接口/类一旦明确了类型之后,我们只能往里面继续操作/放置同样的类型数据。否则错误!!!
另一个接口展示
// // interface Window {
// // [attr: string]: any
// // }
// // window.miaov = 1;
再展示一下范型带来的限制
相比于操作any所有类型,我们想要限制函数去处理任意带有.length属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于T的约束要求。
为此,我们定义一个接口Len来描述约束条件。
泛型约束:
// // function fn<T extends HTMLElement>(a: T) {
// // a.querySelector('div');
// // }
// interface Len {
// length: number
// }
// function fn<T extends Len>(a: T) {
// // 不是所有类型都有length
// a.length
// }
// fn('1');
总结一下
为什么使用泛型
许多时候,标注的具体类型并不能确定,比如一个函数的参数类型。TypeScript 中不建议使用 any 类型,不能保证类型安全,调试时缺乏完整的信息。
TypeScript可以使用泛型来创建可重用的组件。支持当前数据类型,同时也能支持未来的数据类型。扩展灵活。可以在编译时发现你的类型错误,从而保证了类型安全。
泛型的使用
使用泛型可以创建泛型函数、泛型接口,泛型类,支持很广泛,这样让程序更加智能兼容多样化的组件。也提高了组件的重用性。
另外也涉及到了接口,类等,展示了范型的约束,挺多代码的,读者记得多学一下。
就写到这里
我是丸子,每天学会一个小知识。
一个前端开发
希望多多支持鼓励,感谢