一文带你来了解 TypeScript 泛型

2023-11-15 18:44:47 浏览数 (3)

什么是泛型

我们先来看看 ChatGPT 怎么说:

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

泛型优缺点

优点

  1. 类型安全:使用泛型可以让代码在编译时就发现类型错误,避免了运行时类型错误的发生。
  2. 代码复用:泛型可以将一些通用的代码封装成可复用的函数或类,避免了重复编写类似的代码。
  3. 可读性较好:使用泛型可以增强代码的可读性和可维护性,使代码更加易于理解和修改。
  4. 提高性能:泛型代码在 TypeScript 中不需要进行额外的类型检查和类型转换,可以提高程序的运行效率。

缺点

  1. 学习曲线陡峭:与 Java 中一样,使用泛型需要掌握类型参数、泛型方法和通配符等概念,这可能会使初学者感到困惑。
  2. 约束较强:在 TypeScript 中,泛型的类型参数需要满足一定的约束条件,这可能会限制泛型的使用范围和灵活性。
  3. 限制了某些操作:与 Java 中类似,在 TypeScript 中使用泛型时,由于类型参数的不确定性,有些操作是不支持的,例如创建泛型数组、使用 instanceof 运算符等。
  4. 需要考虑类型擦除:与 Java 中类似,泛型在 TypeScript 中也是通过类型擦除实现的,这可能会影响一些泛型代码的实现和设计。

泛型格式

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

  1. 下面代码中,我们定义一个 获取数据的方法 getData ,给它传入了 泛型变量T, 参数类型也是 T, 返回值的类型也是T
代码语言:txt复制
function getData<T>(data : T): T {
    return data
}
  1. 调用函数

它有两种调用方式:

  1. 直接调用,传入参数, 编译器会进行类型推理
  2. 传入指定类型,然后输入的参数必须和指定的类型一致,不然会报错
代码语言:txt复制
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
// }

泛型接口

泛型接口可以这样理解:

当你需要给接口指定类型时,但目前不知道属性类型为什么时,就可以采用泛型接口

你可以给接口指定参数为多个泛型类型,也可以单个;当使用时,明确参数类型即可。

代码语言:txt复制
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' }

泛型类

什么是泛型类

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

泛型类的作用

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

使用格式

代码语言:txt复制
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)

泛型约束

接口约束

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

代码语言:txt复制
# 第一种
// 定义接口
 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: '小新' }

类约束

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

代码语言:txt复制
# 第二种
//  通过类来约束
 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' }

0 人点赞