TypeScript泛型和枚举

156 阅读3分钟

这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战

泛型

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

在开发组件过程中,我们不仅能够支持当前的数据类型,还要支持未来的数据类型,为我们创建大型系统提供了灵活性。

简单例子

我们先来看一个简单例子:实现一个identity函数,它的功能就是传入什么参数的类型,就返回什么类型的返回值,比如,我们传入了一个number类型数据,那么返回值就是number类型的。

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

那如何实现我们开始说的功能呢?可能有人说直接改成any类型就好了,但是那样我们就丧失了对参数类型的约束,并且也不满足我们的需求,使用any的话,当我们传入number类型返回string类型也是满足的,不符合我们的需求,这个时候就用到了范型。

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

在这里,我们使用了 类型变量T,它是一种特殊的变量,只用于表示类型而不是值。TypeScript会帮我们捕获用户传入的类型把它给T,然后我们就可以使用这个类型了,就是传入什么就返回什么类型。

使用泛型变量

还是用上面的例子,我们想打印arg的长度呢?

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

对,如果还想上面那么写他会报错,因为T是任意类型,他不一定有长度,比如数字,没有.length属性,所以他会报错,怎么解决了?比如,我们把它约束成任意类型的数组就好了呀,进行进一步约束。

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

泛型约束

还是上面这个例子,我们到打印arg.length,说明我们传入的参数的有length这个属性呀,那么我们就可以写一个接口来约束我们传入的是任意类型并且该类型有length属性。

interface ILenght {
    length: number;
}

function loggingIdentity<T extends ILenght>(arg: T): T {
    console.log(arg.length);
    return arg;
}

枚举

使用枚举我们可以定义一些带名字的常量,创建一组有区别的用例,TypeScript支持数字的和基于字符串的枚举。

数字枚举

enum Direction {
    Up = 1,
    Down,
    Left,
    Right
}

我们定义了一个数字枚举Direction,他有四个属性,当我们指定Up = 1时,其他三个值会一次从1开始增长,也就是2、3、4,如果我们设置值,默认会从0开始依次增长,如果我们不关心他的值,这种增长是很有用处的。

我们的枚举会被编译成以下内容

var Direction;
(function (Direction) {
   // Direction["Up"] = 1 会返回 1 又作为Direction属性
    Direction[Direction["Up"] = 1] = "Up";
})(Direction || (Direction = {}));

所以我们可以通过Direction.Up来访问我们的值也可以通过Direction[1]来访问我们的Up

字符串枚举

字符串枚举有细微的 运行时的差别。 在字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。他不会自增长,所以我们必须赋予初始值,而且字符串枚举可以很好的序列化。

enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT",
}

异构枚举

枚举可以同时有数字枚举和字符串枚举,但是我们一般都不会这么做的。

enum BooleanLikeHeterogeneousEnum {
    No = 0,
    Yes = "YES",
}