Skip to content

Support inlining strings/const enum string types #3922

Closed
@weswigham

Description

@weswigham

Eg, we should allow

const enum Foo {
    A = "2",
    B = "3"
}

and compile it as we do numerical const enums.
Right now static classes end up getting used for this and don't get typechecked as an enum type - using an string enum clarifies types more, inlining the string clarifies the outputted JS more, and the feature in general could make writing .d.ts files for libs with event names or magic strings much easier. For example, String.normalize is currently defined as:

    /**
      * Returns the String value result of normalizing the string into the normalization form 
      * named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
      * @param form Applicable values: "NFC", "NFD", "NFKC", or "NFKD", If not specified default
      * is "NFC"
      */
    normalize(form?: string): string;

We could get better intellisense and clearer, more self-documenting code with something like so:

const enum UnicodeNormalizationForm {
    NFC = "NFC",
    NFD = "NFD",
    NFKC = "NFKC",
    NFKD = "NFKD",
}

class String {
    normalize(form?: UnicodeNormalizationForm): string;
}

It could also be worth discussing allowing enums in general to be based on arbitrary base types (or at least string/symbol based types, since those are valid object keys), similar to how enums can be based on any numeric type in C#.

Also, in case anyone wasn't aware, for non-const string enums we already emit (mostly) correct code, despite it (technically) being an error to do so - the following compiles without error:

enum Foo {
    A = <any>"A",
    B = <any>"B"
}

console.log(Foo.A);

to

var Foo;
(function (Foo) {
    Foo[Foo['A'] = 'A'] = 'A';
    Foo[Foo['B'] = 'B'] = 'B';
}(Foo || (Foo = {})));
console.log(Foo.A);

without the <any> casts its a type error to do so, however. (And it's pretty simple as to why you probably shouldn't do this - you can corrupt the enum like so):

enum Foo {
    A = <any>"0",
    B = <any>"1",
    C = <any>"A"
}

Foo.A has value "C" rather than "0" in this scenario, thanks to how the emit for enums currently works. However, with const enums this should never be an issue, so I believe that we should start with allowing string const enums.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions