从泛型传递的类型中获取枚举对象

时间:2021-07-26 12:30:21

标签: typescript generics enums

这是一个简化的示例,其思想是一组标签,每个标签由单个字符定义。对象“Flags”累积值 可能的值在枚举中定义。 目标是让源代码明确、简洁、可重构、由编译器验证,并且存储标志的对象紧凑(用于数据库存储)

class Flags<ENU>{
    s: string = "";
    set(v: ENU){
        this.s += v;
        return this;
    }
    has(v: ENU){
        return this.s.includes(v);
    }
}

enum TypeAnimal{
    Winged = "w",
    Legged = "l"
}

let flagsBird = new Flags<TypeAnimal>().set(TypeAnimal.Winged);

我想验证通过这个的枚举没有重复的值。 我认为一种可能性是将类型不是明确地作为泛型传递,而是作为构造函数中的参数传递,让 ts 推断泛型。它似乎几乎可以工作:

class Flags2<ENU>{
    s: string = "";
    constructor(enu: ENU){
        // check here the values in enu, fine.
    }
    set(v: ENU){
        this.s += v;    
        return this;
    }
    has(v: ENU){
        return this.s.includes(v);
    }
}

let flagsBird2 = new Flags2(TypeAnimal);

但这会产生错误:

flagsBird2.set(TypeAnimal.Winged);    // Argument of type 'TypeAnimal' is not assignable to parameter of type 'typeof TypeAnimal'.ts(2345)

我尝试了一些没有奏效的组合(我必须承认有点盲目)。

有什么想法或想法吗? (我觉得这里我有一些关于 ts 和泛型的东西要学习)

2 个答案:

答案 0 :(得分:1)

这种缩短的编码真正给您带来什么好处?

IMO,TypeScript 中的枚举真的不值得。

解决这个问题的惯用方法是使用类型(记住,类型可以是字符串),而不是枚举。 Set 课程免费为您提供重复删除功能。

class Flags3<T extends string>{
    s: Set<string> = new Set();
    constructor(enu: readonly T[]) {
        // check here the values in enu, fine.
    }
    set(v: T) {
        this.s.add(v)
        return this;
    }
    has(v: T) {
        return this.s.has(v);
    }
}

// parameter type below is ("legged" | "winged")[], NOT string[]
const f3 = new Flags3(["legged", "winged"]);

// or
// const animalTypes=["legged","winged"] as const;
// const f3 = new Flags3(animalTypes)

f3.set("legged"); // OK
f3.set("foo"); // compile time error

通过在构造函数参数中指定 readonly T[],我们能够推断传递给它的元组中的各个类型。

Playground Link

Further reading about the downsides of enum

答案 1 :(得分:0)

enum TypeAnimal{
    Winged = "w",
    Legged = "l"
}

// modified class from the question
class Flags2<ENU>{
    s: string = "";
    set(v: ENU){
        this.s += v;    // #todo avoid duplicates in this.s
        return this;
    }
    has(v: ENU){
        return this.s.includes(`${v}`);
    }
}

// version with a Set instead of a string. No duplicates.
class Flags3<ENU>{
    s: Set<ENU> = new Set();
    set(v: ENU){
        this.s.add(v);
        return this;
    }
    has(v: ENU){
        return this.s.has(v);
    }
}

let flagsBird2 = new Flags2<TypeAnimal>();
let flagsBird3 = new Flags3<TypeAnimal>();