TypeScript-generics

前言

泛型是为了构建通用化的组件所设计的,在强类型语言中,泛型是构建大型复杂系统的主要特性之一,它允许将类型定义通用化,而不是单一的形式。

一、基本使用

function doSomeThing(arg: T): T {
  return arg;
}

相比于我们之前学习的类型定义的方式,这里我们多了一个,在TypeScript中,这就叫泛型,表示的语义为,当你调用这个函数的时候除了传递常用的参数,你也可以传递类型,内部会使用传递的这个类型。

比如,我们传递一个string类型:

doSomeThing("mss")

值得注意的是,当你使用了泛型,TypeScript会默认会通过外部传入的类型,推断内部变量或者函数的返回值的类型,并且强制内部的类型要符合外部传入的类型,否则,TypeScript会报错:

function doSomeThing(arg: T): T {
  console.log(arg.length)
  return arg;
}

// Property 'length' does not exist on type 'T'

但是我们有的数据类型就是存在length属性的,那我们这时应该怎么做呢?比如数组来说,TypeScript允许我们直接定义数组的泛型:

function deArr(arg: T[]): T[] {
  console.log(arg.length);
  return arg;
}

此时我们访问length就是合法的。

同时,定义数组的泛型也可以这样写,这种方式和上面那种方式是等效的:

function deAnotherArr(arg: Array): Array {
  console.log(arg.length);
  return arg
}

这种方式也是可以,完全取决于你个人的喜好。

二、使用泛型类型

基本使用

function doSomeThing(arg: T): T {
  console.log(arg.length)
  return arg;
}

let myDoSomeThing: (arg: T) => T = doSomeThing;

传入的类型参数,也可以不用和函数定义的T保持一致:

let myDoSomeThing: (arg: U) => U = doSomeThing;

这样也是可以的。

三、泛型接口

基本使用:

我们首先定义一个泛型接口:

interface GenericInterFace {
  (arg: T): T
}

然后我们这样使用:

let genericInterFace: GenericInterFace = function get(arg: T):T {
  return arg;
}

也可以在定义接口的时候将传入泛型的类型:

interface GenericInterFace {
  (arg: T): T
}

使用的方式和上面的例子一样:

let genericInterFace: GenericInterFace = function get(arg: T):T {
  return arg;
}

此外,前面的例子里面,当我们使用泛型的时候,由于TypeScript编译器不能推断传入的T的类型,当然这也不可能推断,所以当我们试图在内部访问length属性的时候,就会报错。然后,我们这里可以利用接口,在编译之前就给开发一个友好的提示:

定义一个length的接口:

interface Lengthwise {
  length: number;
}

然后重写我们前面的doSomeThing例子:

function doSomeThing(arg: T): T {
  console.log(arg.length)
  return arg;
}

此时就不会报错,这里已经确保了传入的参数必定是有length属性的。

四、泛型类

泛型类在结构上和泛型接口差不多。

class GenericClass {
  name: T
  add: (x: T, y:T) => T
}

然后我们可以正常的通过new关键字进行实例化。

let genericClass = new GenericClass();
genericClass.name = 'mss';

当然,使用泛型的一个好处就是你可以传入任意类型的类型参数:

let genericClass = new GenericClass();

这也是合理的。

五、泛型的高级用法

1、使用泛型确保访问对象时不会访问到对象不存在的属性。

定义一个泛型

function getProperty(obj: T, key: K) {
  return obj[key];
}

注意这里是的keyof是TypeScript中给我们提供的遍历对象属性值的操作符。

然后我们这样使用:

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a");
// 1

getProperty(x, "m");
// Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.

2、类的构造函数和泛型一起使用

function create(c: { new (): T }): T {
  return new c();
}

你可能感兴趣的:(TypeScript-generics)