TS基础篇:泛型的理解


当我们定义一个变量不确定类型的时候有两种解决方式:

  • 使用any
    • 使用any定义时存在的问题:虽然 以 知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势
  • 使用泛型
    • 泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。

泛型

泛型可以理解为宽泛的类型,通常用于类和函数

设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。

为了便于大家更好地理解上述的内容,我们来举个例子,在这个例子中,我们将一步步揭示泛型的作用。首先我们来定义一个通用的 identity 函数,该函数接收一个参数并直接返回它:

function identity (value) {
    return value;
}

console.log(identity(1)) // 1

现在,我们将 identity 函数做适当的调整,以支持 TypeScript 的 Number 类型的参数:

function identity (value: Number) : Number {
    return value;
}

console.log(identity(1)) // 1

这里 identity 的问题是我们将 Number 类型分配给参数和返回类型,使该函数仅可用于该原始类型。但该函数并不是可扩展或通用的,很明显这并不是我们所希望的。

我们确实可以把 Number 换成 any,我们失去了定义应该返回哪种类型的能力,并且在这个过程中使编译器失去了类型保护的作用。我们的目标是让 identity 函数可以适用于任何特定的类型,为了实现这个目标,我们可以使用泛型来解决这个问题,具体实现方式如下:

function identity (value: T) : T {
    return value;
}

console.log(identity(1)) // 1

对于刚接触 TypeScript 泛型的读者来说,首次看到 <T> 语法会感到陌生。但这没什么可担心的,就像传递参数一样,我们传递了我们想要用于特定函数调用的类型。

参考上面的图片,当我们调用 identity<Number>(1)Number 类型就像参数 1 一样,它将在出现 T 的任何位置填充该类型。图中 <T> 内部的 T 被称为类型变量,它是我们希望传递给 identity 函数的类型占位符,同时它被分配给 value 参数用来代替它的类型:此时 T 充当的是类型,而不是特定的 Number 类型。

其中 T 代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T 可以用任何有效名称代替。除了 T 之外,以下是常见泛型变量代表的意思:

  • K(Key):表示对象中的键类型;
  • V(Value):表示对象中的值类型;
  • E(Element):表示元素类型。

其实并不是只能定义一个类型变量,我们可以引入希望定义的任何数量的类型变量。比如我们引入一个新的类型变量 U,用于扩展我们定义的 identity 函数:

function identity (value: T, message: U) : T {
    console.log(message);
    return value;
}

console.log(identity(68, "Semlinker"));

泛型约束

interface Person {
    name:string;
    age:number;
}
function student(arg:T):T {
      return arg;
}

student({name:'lili'});//类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性
student({ name: "lili" , age:'11'});//不能将类型“string”分配给类型“number”
student({ name: "lili" , age:11});

参考:一文搞懂 TS 泛型,让你头不再晕


文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录