使用枚举作为通用类型

时间:2019-06-17 06:50:04

标签: typescript

我正在尝试实现一些类似于以下功能:

enum MyEnum {
   ONE = "ONE", 
   TWO = "TWO"
}

interface MyInterface<T extends enum> { //Obviously wrong syntax
    value: T; //Use a single value of the enum
    values: Record<T, number>; //Use all of the keys of the enum
    optionalValues: Record<T?, number>; //Use only the keys of the enum, but not necessarily all of them. 
}


const a : MyInterface<MyEnum>  = {
    value: "ONE",  //OK
    values: {
       ONE: 1,    //OK
       TWO: 2, 
       THREE: 3 //NOT OK 
    }, 
    optionalValues: {
       ONE: 111,   //OK
       THREE: 3    //NOT OK 
    }
}

const b : MyInterface<MyEnum>  = {
    value: MyEnum.ONE,  //OK
    values: {
       ONE: 1,    //Not ok - not all enum values used
    }, 
    optionalValues: {
       [MyEnum.ONE]: 111,   //Ok, and generally this is the way I want to be using this. 
    }
}


也就是说-我希望能够使用枚举来指定键列表,然后将接口定义为包含这些键的对象。

即。

const iceCreams = MyInterface<IceCreamFlavours> = {
   ...
}

const fruit = MyInterface<FruitTypes> = {
    ...
}

我该如何实现?这似乎是一个相当普遍的用例。

1 个答案:

答案 0 :(得分:1)

没有enum约束。枚举可以是stringnumber,因此约束string | number是我们能做的最好的事情:

interface MyInterface<T extends string | number> {
    value: T; //Use a single value of the enum
    values: Record<T, number>; //Use all of the keys of the enum
    optionalValues: Partial<Record<T, number>>; //Use only the keys of the enum, but not necessarily all of them. 
}

enum MyEnum {
   ONE = "ONE", 
   TWO = "TWO"
}

const a : MyInterface<MyEnum>  = {
    value: MyEnum.ONE,  //OK
    values: {
       [MyEnum.ONE]: 1,    //OK
       [MyEnum.TWO]: 2, 
       [MyEnum.THREE]: 3 //NOT OK 
    }, 
    optionalValues: {
       [MyEnum.ONE]: 111,   //OK
       [MyEnum.THREE]: 3    //NOT OK 
    }
}

我们还可以使用枚举成员名称,但是我们必须传入枚举容器对象的类型,而不是枚举的类型。

interface MyInterface<T extends Record<keyof T, string | number>> { // enum like object 
    value: keyof T; //Use a single value of the enum
    values: Record<keyof T, number>; //Use all of the keys of the enum
    optionalValues: Partial<Record<keyof T, number>>; //Use only the keys of the enum, but not necessarily all of them. 
}

enum MyEnum {
ONE = "ONE", 
TWO = "TWO"
}

const a : MyInterface<typeof MyEnum>  = {
    value: "ONE",  //OK
    values: {
    "ONE": 1,    //OK
    "TWO": 2, 
    "THREE": 3 //NOT OK 
    }, 
    optionalValues: {
    "ONE": 111,   //OK
    "THREE": 3    //NOT OK 
    }
}