TS泛型详解(上)

885 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

序言

作为TS 的核心之一泛型,总是让人有很多不解的地方,那么究竟什么是泛型?有什么作用?如何使用?今天我们带着问题一一探寻

泛型的定义

TS 中,泛型表示 泛指某一个类型, 开发者可以指定一个表示类型的变量,用他来作为实际类型的占位符 ,用尖括号来包裹类型变量<T>

泛型的作用

用作创建可重用的组价,从而让一个组件可以支持多种数据类型,它可以作用在接口,类,函数或者类型别名上。

普通定义

我们通过一个例子来体验一下泛型的作用

//我们在TS 中定义一个 infoCenter 用于展示用户的信息
function infoCenter (age: number,name:string) : string{
  return `我是${name},我${age}岁`;
}
​
console.log(infoCenter(24,'coolFish')) // "我是coolFish,我24岁" 

上例中,我们定义了infoCenter 的方法,入参我们限定了age 为 number,名字为string,使该函数仅可用于该原始类型number,string。 所以该函数并不是通用的,例如,name限定为string,不能使用number,。虽然我们可以把 string 换成 any,但这样的话,我们失去了定义应该返回哪种类型的能力,并且在这个过程中使编译器失去了类型保护的作用。

泛型定义

我们如果要让 userCenter 可以适用于任意的类型,那就需要用到泛型

function infoCenter (age : T,name : U) : U{
  return `我是${name},我${age}岁`;
}
​
console.log(infoCenter<Number, string>(24,'coolFish')) // "我是coolFish,我24岁" //我希望name 为Number
console.log(infoCenter<Number, Number>(24, 6666)) // "我是6666,我24岁" 

这样我们就能灵活的配置,我们的入参用什么类型的参数。

小结:

泛型参数就像函数中的类型参数一样,都是一个占位符,函数中是占 入参值,泛型占的类型,在输入时,会自动分配到相应的位置,就像上例,Number 会分配给 T, string 会分配给 U。

泛型接口

要解决函数中返回多种类型对象的问题,我们可以创建一个用于 infoCenter 的通用 infoCenters接口

interface Identities<T, U> {
  age: T,
  name: U
}

定义完infoCenters接口后,我们可以把该接口作为 infoCenter 的返回值类型。

function identity<T, U> (age: T, name: U): Identities<T, U> {
  console.log(age + ": " + typeof (age));
  console.log(name + ": " + typeof (name));
  let identities: Identities<T, U> = {
    age,
    name
  };
  return identities;
}
​
console.log(identity(25, "coolFish"));
​
//  25: number
//  coolFish: string
//  {age: 68, name: "coolFish"}

由此,我们知道,泛型接口不仅仅可以作用于函数,还可以作用于返回值。同样,还可以作用在类里面

泛型类

泛型接口约束的是方法,泛型类约束是类。使用的话也简单,在类的后面使用<T,...> 的语法定义任意多个类型变量。

interface GenericInterface<U> {
  value: U
  getIdentity: () => U
}
​
class IdentityClass<T> implements GenericInterface<T> {
  value: T
​
  constructor(value: T) {
    this.value = value
  }
​
  getIdentity(): T {
    return this.value
  }
}
​
const myNumberClass = new IdentityClass<number>(25);
console.log(myNumberClass.getIdentity()); // 25const myStringClass = new IdentityClass<string>("coolFish!");
console.log(myStringClass.getIdentity()); // coolFish!

我们注意到,这和实现接口一样,类里面得实现,泛型类里定义的内容。