TypeScript中的泛型
1.1 泛型的定义
泛型:软件工程中,我们不仅要创建一致的定义 良好的API,同时也要考虑可重用性。组件不仅能够支持当前的数据类
型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,’ 个组件可以支持多 种类型的数据。 这样用户就可以
以自己的数据类型来使用组件。
I
通俗理解:泛型就是解决类接口方法的复用性、以及对不特定数据类型的支持。
1.2 泛型函数
/**
* 泛型的举例
*/
//只能返回string类型的数据
function getData(value: string): string {
return value;
}
//同时返回string类型和number
//方法1:类型定义两个函数,缺点代码冗余
function getData1(value: string): string {
return value;
}
function getData2(value: number): number {
return value
}
//方法2:使用any 缺点,相当于放弃了类型检测
function getData3(value: any): any {
return value;
}
/**
* 需求:传入什么返回什么类型(传入的参数和返回的参数一致)
* 例如:传入number返回number 传入string返回string
* 方法:使用泛型,可以支持不特定的数据类型
* T表示泛型,具体是什么类型调用这个方法的时候决定的
*/
function getData4<T>(value: T): T {
return value;
}
// 调用
console.log(getData4<number>(123));
console.log(getData4<string>('kjh'));
// 同时我们可以任意指定返回的类型参数为any等
function getData5<T>(value: T): any {
return value;
}
1.3 泛型类
/**
* 泛型类的举例
* 泛型类:比如有个最小堆算法,需要同时支持返回数字和字符串两种类型。
* 通过类的泛型来实现
*/
class minClass {
public list: number[] = [];
add(num: number) {
this.list.push(num);
}
minNumber(): number {
var minNum = this.list[0];
for (var i = 0; i > this.list.length; i++) {
if (minNum > this.list[i]) {
minNum = this.list[i]
}
}
return minNum;
}
}
//使用minClass
var m = new minClass();
m.add(1)
m.add(2)
m.add(10)
m.add(99)
console.log(m.minNumber());
//1
/**
* 问题来了,上面我们封装的类不能满足传入字符串返回字符串,传入数字返回数字的要求
* 方法:使用泛型类解决问题
*/
class minClass2<T>{
public list:T[] = [];
add(value:T):void{
this.list.push(value);
}
minNumber():T{
var minNum = this.list[0];
for (var i = 0; i > this.list.length; i++) {
if (minNum > this.list[i]) {
minNum = this.list[i]
}
}
return minNum;
}
}
//调用泛型类
//实例化类 并且制定了类的T代表的类型是number
var m1 = new minClass2<number>();
m1.add(1)
m1.add(2)
m1.add(3)
console.log(m1.minNumber()); //1
//实例化类 并且制定了类的T代表的类型是string
var m2 = new minClass2<string>();
m2.add('a')
m2.add('b')
m2.add('c')
console.log(m2.minNumber()); //a
1.4 泛型接口
/**
* 泛型接口
*/
/**
* 先定义一个函数接口
* 缺点:只能传入string类型
*/
interface ConfigFn{
(value1:string,value2:string):string;
}
var setData:ConfigFn = function(value1:string,value2:string):string{
return value1 + value2;
}
console.log(setData('name','张三'));
/**
* 第一种定义泛型的方法
* 使用泛型接口
* 要求:按照我们传入的数据类型进行判断
*/
interface ConfigFn2 {
<T>(value:T):T;
}
var getData:ConfigFn2 = function<T>(value:T):T{
return value;
}
console.log(getData<string>('张三'));
console.log(getData<number>(999));
/**
* 第二种定义泛型的方法
* 使用泛型接口
* 要求:按照我们传入的数据类型进行判断
*/
interface ConfigFn3<T>{
(value:T):T;
}
var myGetData:ConfigFn3<string> = function<T>(value:T):T{
return value;
}
console.log(myGetData('20'))
2.1 深入泛型类(超级重点)
- 把类作为参数来约束数据传入的类型:定义一个User的类这个类的作用就是映射数据库字段
然后定义一个MysqlDb的类这个类用于操作数据库,之后把user类作为参数传,入到MysqlDb中
/**
* 解释:把类作为参数来约束数据传入的类型
* 定义一个User的类这个类的作用就是映射数据库字段
* 然后定义一个MysqlDb的类这个类用于操作数据库
* 后把user类作为参数传,入到MysqlDb中
*/
//User类来映射数据库字段
class User{
userName:string | undefined;
passWord:string | undefined;
}
//定义一个MysqlDb的类这个类用于操作数据库
class MySqlDB{
add(user:User):boolean{
console.log(user);
return true;
}
}
var u = new User();
u.userName = 'admin';
u.passWord = '123456';
var Db = new MySqlDB();
Db.add(u);
//User {userName: "admin", passWord: "123456"}
/**
* 接下来我们再定义一个文章类
*/
class Article{
title:string | undefined;
status:string | undefined;
desc:string | undefined;
}
//定义一个MysqlDb的类这个类用于操作数据库
class MySqlDB2{
add(article:Article):boolean{
console.log(article);
return true;
}
}
var a = new Article();
a.title = '时间去哪儿了'
a.status = '200'
a.desc = '宝鸡新闻网'
var Db2 = new MySqlDB2();
Db2.add(a);
//Article {title: "时间去哪儿了", status: "200", desc: "宝鸡新闻网"}
- 但是我们发现一个问题,如果数据库中有多个字段,我们需要每次重新定义mysqlDB类
/**
* 问题:如果数据库中有多个字段,我们需要每次重新定义mysqlDB类
* 解决:使用泛型类解决重复封装
*/
//定义操作数据库的泛型类
class MysqlDB<T>{
add(info: T): boolean {
console.log(info);
return true;
}
}
//这时候我想定义一个User类
class User {
userName: string | undefined;
passWord: string | undefined;
}
var u = new User();
u.userName = 'admin'
u.passWord = '123456'
//使用User类来约束泛型类
var DB = new MysqlDB<User>();
//我又想定义一个Aritcile类
class Article {
title: string | undefined;
status: string | undefined;
desc: string | undefined;
}
var a = new Article();
a.title = '时间去哪儿了'
a.status = '200'
a.desc = '宝鸡新闻网'
var Db2 = new MysqlDB<Article>();
//这样我一个泛型类,可以给多个数据库字段使用
//实例化的时候进行传值
class Person{
name:string | undefined;
age:number|undefined;
id:number | undefined;
constructor(params:{
name:string | undefined,
age:number | undefined,
id?:number | undefined
}){
this.name = params.name;
this.age = params.age;
this.id = params.id;
}
}
var p = new Person({
name:'张三',
age:20
})
var db = new MysqlDB<Person>();
- 数据库修改
/**
* 修改数据库数据
*/
//定义操作数据库的泛型类
class MysqlDB<T>{
//增加
add(info: T): boolean {
console.log(info);
return true;
}
//修改
updata(info:T,id:number):boolean{
console.log(info)
console.log(id);
return true;
}
}
class Person{
name:string | undefined;
age:number|undefined;
id:number | undefined;
constructor(params:{
name:string | undefined,
age:number | undefined,
id?:number | undefined
}){
this.name = params.name;
this.age = params.age;
this.id = params.id;
}
}
var p = new Person({
name:'张三',
age:20
})
var db = new MysqlDB<Person>();
db.updata(p,12);
//Person {name: "张三", age: 20, id: undefined}
p.id = 12;
db.updata(p,12);
// Person {name: "张三", age: 20, id: 12}