TS笔记之 泛型

2021-06-23  本文已影响0人  伶念

泛型

介绍

软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。

泛型之 Hello World

这个函数会返回任何传入它的值

function identity<T>(arg: T): T {
  return arg;
}

\color{#bf414a}{泛型} 有两种方法使用:

1.传入所有的参数,包含类型参数:

let output = identity<string>("myString"); // type of output will be 'string'

2.类型推论 -- 编译器会根据传入的参数自动地帮助我们确定 T 的类型

let output = identity("myString"); // type of output will be 'string'

使用泛型变量

把泛型变量 T 当做类型的一部分使用,而不是整个类型,增加了灵活性

function loggingIdentity<T>(arg: Array<T>): Array<T> {
  console.log(arg.length); // Array has a .length, so no more error
  return arg;
}

泛型类型

泛型接口:

interface GenericIdentityFn<T> {
  (arg: T): T;
}

function identity<T>(arg: T): T {
  return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

除了泛型接口,我们还可以创建泛型类。 注意,无法创建泛型枚举和泛型命名空间。

泛型类

泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。

class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
  return x + y;
};

泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。

泛型约束

我们想要限制函数去处理任意带有.length 属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于 T 的约束要求。

为此,我们定义一个接口来描述约束条件。 创建一个包含 .length 属性的接口,使用这个接口和 extends 关键字来实现约束:

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // Now we know it has a .length property, so no more error
  return arg;
}

现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:

loggingIdentity(3); // Error, number doesn't have a .length property

在泛型约束中使用类型参数

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

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

getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.

在泛型里使用类类型

在 TypeScript 使用泛型创建工厂函数时,需要引用构造函数的类类型

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

一个更高级的例子,使用原型属性推断并约束构造函数与类实例的关系。

class BeeKeeper {
  hasMask: boolean;
}

class ZooKeeper {
  nametag: string;
}

class Animal {
  numLegs: number;
}

class Bee extends Animal {
  keeper: BeeKeeper;
}

class Lion extends Animal {
  keeper: ZooKeeper;
}

function createInstance<A extends Animal>(c: new () => A): A {
  return new c();
}

createInstance(Lion).keeper.nametag; // typechecks!
createInstance(Bee).keeper.hasMask; // typechecks!
上一篇下一篇

猜你喜欢

热点阅读