TypeScript - 泛型解析Generics

泛型

主要用于创建重用组件,允许用户去使用自己的类型去重用这些组件。

如何定义泛型?

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

对比一下

function identity(arg: any): any {
    return arg;
}

就很容易理解了,实际上就是运用了一个变量T去捕捉用户提供的类型 (例如: number, string),然后再使用T作为返回值类型。那为什么要使用泛型而不使用any. 主要是为了保证输入输出的类型都一致。比如下面这个例子,明确指出传入的参数类型是number,返回值类型是number.

function identity(arg: number): number {
    return arg;
}

如何使用泛型?

两种方式:
1.明确设置T的值
2.编译器根据传入的参数类型自动设置T的值

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

let output1 = identify<string>('my String'); //方式一
let output2 = identify('my String'); //方式二

泛型接口

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

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

let myIdentity: GenericIdentityFn<number> = identity;

myIdentity('string')// error
myIdentity(123) //correct

泛型类

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

//定义成number类型

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

console.log(myGenericNumber.add(myGenericNumber.zeroValue, 2));

//定义成string类型

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };

console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));

泛型里面调用通用属性

function loggingIdentity<T>(arg: T): T {
    console.log(arg.length);  // Error: T doesn't have .length
    return arg;
}

上面这个例子原意是想设置一个通用函数,但是呢,翻译器无法确定每种类型都具有.length属性。所以它不高兴,让你不要做这种假设。

那么如何解决呢?
第一种方式把 T设置成数组,告诉编译器传进来的类型具有.length方法,不需要担心

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

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

第二种
具有length属性的除了数组,字符串也有嘛。光是上一种方法不能最大化我们的需求。就只有寻求第二种方式“给T设置约束”

设置一个接口给T继承,明示翻译器。限制了传进来的参数都是具有length属性的。不然就会报错. (官方称之为”通用约束”)

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(123); // error!!!
loggingIdentity({length: 10, value: 3});
loggingIdentity([1,2,3]);
loggingIdentity('string');

通用约束中使用变量参数

function getProperty<T, K extends keyof T>(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'.

用泛型写工厂类型

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;
  constructor(){
    super();
    this.keeper = new BeeKeeper();
  }
}

class Lion extends Animal {
  keeper: ZooKeeper;
  constructor(){
    super();
    this.keeper = new ZooKeeper();
  }
}

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

createInstance(Lion).keeper.nametag;  // typechecks!
createInstance(Bee).keeper.hasMask;   // typechecks!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值