泛型

介绍

为了擦黄健一致的良好的API,组件在支持当前数据类型的基础上,还需要支持未来的数据类型

需求:创建一个函数接收一个参数,并将这个参数返回
对于这样的函数,如果对输入的参数类型使用any。那么就会丢失信息,即传入的类型与返回的类型是相同的。因此我们可以使用类型变量来解决这个问题,类型变量是一种特殊的变量,只用于表示类型而不是值。这样可以是我们追踪函数里的类型信息。

  1. function identity<T>(arg:T):T{
  2. return arg;
  3. }

这个 identity函数叫做泛型。

  1. let output=identity<string>("myString) // 方法1
  2. let output=indentity("myString)``// 方法2

其中第二种方法更加普遍,利用了类型推论。一般的编译器会查看myString的值,然后把T设置为他的类型。当然也存在编译器不能自动推断出类型的情况。这是只能使用方法1.

使用泛型变量

使用泛型变量,必须把传入的参数当作任意的类型。

理解loggingIdentity的类型:泛型函数loggingIdentity,接收类型参数T和参数arg,它是个元素类型是T的数组,并返回元素类型是T的数组。 如果我们传入数字数组,将返回一个数字数组,因为此时 T的的类型为number。 这可以让我们把泛型变量T当做类型的一部分使用,而不是整个类型,增加了灵活性。

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

泛型类型

如何创建泛型接口

  1. function identity<T>(arg: T): T {
  2. return arg
  3. }
  4. let myIdentity: <T>(arg: T) => T = identity;
  5. // 使用不同的泛型参数名
  6. let myIdentity2: <U>(arg: U) => U = identity;
  7. // 使用带有调用签名的对象字面量来定义泛型函数
  8. let myIdentity3: { <T>(arg: T): T } = identity;
  9. // 泛型接口
  10. interface GenericIdentityFn {
  11. <T>(arg: T): T
  12. }
  13. let myIdentity4: GenericIdentityFn = identity;
  14. // 把泛型参数当成接口的参数
  15. interface GenericIdentityFn2<T> {
  16. (arg: T): T;
  17. }
  18. let myIdentity5: GenericIdentityFn2<number> = identity;

泛型类

泛型类使用(<>)括起泛型类型,跟在类名后面。泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。

  1. class GenericNumber<T> {
  2. zeroValue: T;
  3. add: (x: T, y: T) => T
  4. }
  5. let myGenericNumber = new GenericNumber<number>();
  6. myGenericNumber.zeroValue = 0;
  7. myGenericNumber.add = function (x, y) {
  8. return x + y;
  9. };
  10. let stringNumeric = new GenericNumber<string>();
  11. stringNumeric.zeroValue = '0';
  12. myGenericNumber.add = function (x, y) {
  13. return x + y;
  14. };
  15. console.log(stringNumeric.add(stringNumeric.zeroValue, 'test'))

泛型约束

限制函数去处理任意带有length属性的所有类型。只要类型传入有这个属性就允许。增加泛型约束后,则必须传入符合约束的类型的值

  1. interface Lengthwise {
  2. length: number;
  3. }
  4. function loggingIdentity<T extends Lengthwise>(arg:T):T {
  5. console.log(arg.length);
  6. return arg
  7. }

泛型约束中使用类型参数

需求:确保属性在某个对象上。

  1. function getProperty(obj: T, key: K) {
  2. return obj[key];
  3. }
  4. let x = {a: 1, b: 2, c: 3, d: 4};
  5. getProperty(x, "a");

在泛型里使用类类型

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

  1. function create<T>(c: { new(): T }): T {
  2. return new c();
  3. }

使用原型属性推断并约束构造函数与类实例的关系

  1. class BeeKeeper {
  2. hasMask: boolean
  3. }
  4. class ZooKeeper {
  5. nameTag: string;
  6. }
  7. class Animal {
  8. numLegs: number;
  9. }
  10. class Bee extends Animal {
  11. keeper: BeeKeeper;
  12. }
  13. class Lion extends Animal {
  14. keeper: ZooKeeper;
  15. }
  16. function createInstance<A extends Animal>(c: new() => A): A {
  17. return new c();
  18. }
  19. createInstance(Lion).keeper.nameTag; //typeChecks
  20. createInstance(Bee).keeper.hasMask; //typeChecksa