【问题标题】:Specify enum type指定枚举类型
【发布时间】:2018-03-01 09:09:00
【问题描述】:

有枚举:

enum Foo {
    Bar, // should cause type error
    Baz = 'Baz'
}

是否可以为其指定类型以使其成为纯字符串枚举?

【问题讨论】:

    标签: typescript enums


    【解决方案1】:

    如果需要,您可以执行以下操作:

    创建一个要求其输入仅具有string-valued 属性的函数:

    const enforceStringEnum = <E extends Record<keyof E, string>>(e: E) => {};
    

    然后,根据需要声明Foo:

    enum Foo {
      Bar, 
      Baz = 'Baz'
    }
    

    并以Foo 作为输入调用函数:

    enforceStringEnum(Foo); // error!
    // Type 'Foo.Bar' is not assignable to type 'string'.
    

    这会给你一个关于Foo.Bar的错误消息,你可以返回并修复它以消除错误。

    是的,您得到的错误不是 Foo 声明的本地错误,但它确实允许您将 Foo 保留为 enum,而不是使用其他一些语言结构。是的,enforceStringEnum() 在运行时有一个(非常小的)影响。如果您根本不想拥有运行时工件,这是可能的,但(在我看来)有点丑陋:

    type EnforceStringEnum<E extends Record<keyof E, string>> = true;
    
    enum Foo {
      Bar,
      Baz = 'Baz'
    }
    
    declare var fooWitness: EnforceStringEnum<typeof Foo>; // error! 
    // Type 'Foo.Bar' is not assignable to type 'string'.
    

    但它的工作方式相同。

    编辑:或者,正如@estus 提到的,您可以使用类型别名而不是变量声明:

    type FooWitness = EnforceStringEnum<typeof Foo>; // error!
    // Type 'Foo.Bar' is not assignable to type 'string'.
    

    希望对您有所帮助。祝你好运!

    【讨论】:

    • 谢谢,最近才有机会检查这个答案。这是一个非常巧妙的技巧。我担心declare 命名空间污染,我认为单独使用类型进行类型检查可以更好地达到目的。如果您知道如何以更好的方式解决this,我将不胜感激。
    • 类型别名见证也是一个好主意。无论哪种方式(declare var 或 type)都会将不必要的名称添加到命名空间(值或类型),因此由您决定要执行哪个名称。类型更干净,但您可以多次重新声明相同的var(只要类型相同),这样您就可以减少对命名空间的污染。
    【解决方案2】:

    如果你检查为你的枚举生成的 JS 代码,你会发现它等价于

    enum Foo {
        Bar = 0, // should cause type error
        Baz = 'Baz'
    }
    

    但允许在 TypeScript 中创建此类枚举,请参阅 Heterogeneous Enums。

    你也可以使用命名空间:

    namespace Foo {
        export const Bar: string = "Foo";
        export const Baz: string = "Baz";
    }
    

    或具有静态字段的类:

    class Foo {
        static Bar: string = "Foo";
        static Baz: string = "Baz";
    }
    

    第一个好处是Foo中只有Bar和Baz属性,没有别的。

    【讨论】:

    • 没错。我正在寻找一种方法,不让开发人员(我)在需要异构枚举的地方意外创建混合枚举。
    • “在需要异构枚举的地方意外创建混合枚举”是什么意思?
    • 目的是强制 Foo 为纯字符串枚举。 Bar 或 Bar = 0 应该会导致类型错误。
    • 我认为目前不可能,使用字符串文字联合类型怎么样,例如type Foo = "Bar" | "Baz"?这样您甚至不需要使用前缀Foo 并直接发送"Bar" 和"Baz"。
    • 我牢记type Foo,但我的意图是摆脱原始字符串,因为Baz 属性值可以是一个长字符串。
    猜你喜欢
    • 2012-03-10
    • 2011-06-20
    • 2012-09-16
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    • 2018-10-18
    • 2017-01-14
    相关资源
    最近更新 更多