Typescript: Compiling TS with enum strings for 2-way mapping (the old way) causes invalid declaration file (but compiles ok).

Created on 27 Oct 2017  Â·  15Comments  Â·  Source: microsoft/TypeScript

I noticed something seems inconsistent. I have a mapping that was working for mapping file types and extensions, which was VERY convenient, and allowed tracking them as proper types (other than string). The .d.ts file is generated ok, without errors! However, if I take that declaration file and add it to another project it breaks.

TypeScript Version: 2.5 (that is the only version I have that was updated with VS 2017)

Code

enum FileTypesMap {
    FileTypeAExt = <any>".aext",
    FileTypeBExt = <any>".bext"
}
enum FileTypesMap {
    FileTypeCExt = <any>".cext",
    FileTypeDExt = <any>".dext"
}

Expected behavior:

file.d.ts output:

declare enum FileTypesMap {
    FileTypeAExt = <any>".aext",
    FileTypeBExt = <any>".bext"
}
declare enum FileTypesMap {
    FileTypeCExt = <any>".cext",
    FileTypeDExt = <any>".dext"
}

_(or similar, doesn't matter)_

Actual behavior:

file.d.ts output:

declare enum FileTypesMap {
    FileTypeAExt,
    FileTypeBExt,
}
declare enum FileTypesMap {
    FileTypeCExt,
    FileTypeDExt,
}

ERROR: In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element.

Yes, I am well aware of the issues of enum { A = <any>'B', 'B' = <any>'A' }, and that's besides the point. If it compiles correctly, the d.ts file should also be proper - it should not be complaining about implementation stuff. ;)

I'm also aware of string enums, and that is also not the point of this code. The point is a mapping between a file type name and an extension (both ways). There are other ways I'm sure, which is also not the point since this should work. Keep in mind this is part of a framework that also allows others to extend the file type names and extensions. I imagine there are other ways, but if this way compiles, again, the declaration should not be complaining.

Working as Intended

Most helpful comment

And this is pretty!?

enum FileTypesMap {
    FileTypeAExt = <any>".aext",
    FileTypeBExt = <any>".bext"
}

🤷‍♂️

All 15 comments

Do not use numeric enums to add strings. that is not a supported behavior.

Starting from TS 2.4, you can use string enums

I should add that the "expected" behavior you list never worked.

As I stated, I can use string enums, which I already know. It compiles just fine, so it should be supported. I don't see why declarations should be failing for something that compiles, which makes no sense at all. If you don't want to support it, then make it fail at compile time; otherwise, people will do it, then complain, only to have TS guys say "yes, the compiler supports it, but the .d.ts doesn't!" lol ;) (and that is not working as intended - at least it shouldn't be)

It compiles just fine

no. consider FileTypesMap.FileTypeAExt.toFixed(), this will fail at runtime with string.toFixed is not a funciton.

so it should be supported.

no. it was not supported. we never claimed it was.

If you don't want to support it, then make it fail at compile time

we do. you casted your way to any. same as (<any>"string").toFixed(); that one is not supported either.

Yes, that will fail, of course, but I'm not using it that way, and as I said, it does not fail the way I put it (only the way you put it). ;) What I mean is that I used it that way since last year+ (for strong typing before string enums) and it worked just fine - because I knew it wasn't a number!!! ;) Anyhow, I didn't realize was still treated as a number type (which makes sense) so I do get it. It would be nice if we allowed some sort of string mapping this way, but I guess I'll have to use another workaround, as typical again. TS is great, except when you try to do stuff you know should work perfectly fine in JS, but it fights with you (like this). I guess I'll just use string enums and create a function to make this mapping instead; certainly less 'framework' friendly.

when you try to do stuff you know should work perfectly fine in JS

Enums are a TypeScript only construct... so no, it never worked perfectly fine in JS.

Lol, I know that, give me some credit. :P I mean the JavaScript that gets output from TypeScript I can use to do what I want. I don’t need to use a TypeScript enum when I can easily do THAT (output) manually. First there was resistance against string enums, then finally it came, but they took away any ability to do a reverse mapping because they figure someone people would hurt themselves so now we have string enums, but limited, forcing people to mimic the mapping with more work that I felt should be necessary. In the end I simply had to write a function to turn string enums into the same behavior as numeric enums; perhaps decorators can be use on enums one day. ;)

BTW I can appreciate (like C#) enums are numbers, but we do now have enum strings. Dual mapping for strings would be a really neat feature (where appropriate [like file types and extensions above], and people should be warned to use it correctly), but it's just a thought. I'd welcome at least the ability to add decorators to string enums to do this at least. ;) Again, just my 2 cents - 'take it and go' (Russle Peters). ;)

You can trivially construct the dual map yourself. There's no reason for TS to complicate itself with this.

As I already mentioned, yes. ;) Just not as “pretty”, and a lot less end-user friendly for extending.

And this is pretty!?

enum FileTypesMap {
    FileTypeAExt = <any>".aext",
    FileTypeBExt = <any>".bext"
}

🤷‍♂️

I don't recall saying it was pretty at all. ;) Besides, do you have a better idea to accomplish the same 2-way mapping without it looking worse? I suppose you think this looks better?

FileTypesMap[FileTypesMap["FileTypeAExt"] = ".aext"] = "FileTypeAExt";
FileTypesMap[FileTypesMap["FileTypeBExt"] = ".bext"] = "FileTypeBExt";

Any developer worth their weight in salt would know sometimes you have to work around limitations in languages and find the simplest way possible in that language, and it's not always pretty, but then there's not much choice except to make it look worse.

BTW: I'm not advocating for it to work with <any>, all I said was "it compiles fine, and the declaration is in error", that is all. If the declaration file is in error, this should not be allowed compile time. Obviously it goes without saying not having to use <any> would be better. I understand why string enums are limited, because novices will use it incorrectly, but still, it would be nice to be able to push this intent in some TS supported way without having to resort to workarounds. Again, just my 2 cents, take it or leave it I don't care, I already have a workaround. ;) I am happy at the progress TS made thus far since it started (and I've been working with it since then). Things are much better now than they used to be (by far!), and supporting string enums, even limited, is awesome, so good job TS team. ;)

For the record, I just did something like this (to allow extending the list by external users):

enum FileTypesMap {
    FileTypeAExt = ".aext",
    FileTypeBExt = ".bext"
}
map(FileTypesMap);

Again, as I said, not pretty, but it's still better than other alternatives. I want to see TS become the best, and so I just like challenging some ideas and putting stuff out there - well received or not. ;)

BTW: I'm building a 2D world particle simulation game engine (experiment at least), which, at the moment, runs calculations mostly in the GPU (or worker threads [can switch back and forth]), with my own WebGLJS wrapper library I whipped up last week. I was creating a resource loader (copied from some old code - before string enums) and had mappings between MIME-types and names, which failed when I tried to use the d.ts file, hence the original post.

I don't recall saying it was pretty at all. ;)

This issue is to restore a non-pretty unintentional side-effect. With your last statement, your justification for dismissing the workaround wasn't pretty, therefore I concluded the unintentional side-effect feature you want support was pretty.

No it wasn’t. The original intention was to make sure the d.ts stayed consistent to the successfully compiled code. How it looks was not relevant to this at all. Also, I said “as pretty” which means other work-arounds are “more ugly”, and that was all. I think you missed my original point. The fact you even said that shows you don’t like it either, which just further proves my point that it would be nice not to use “any” at all and suppprt this in string enums instead somehow (both ways), but in the end there are “less pretty” work arounds, yes. Also, constructive criticism is better than sarcasm. :P

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wmaurer picture wmaurer  Â·  3Comments

Zlatkovsky picture Zlatkovsky  Â·  3Comments

dlaberge picture dlaberge  Â·  3Comments

siddjain picture siddjain  Â·  3Comments

seanzer picture seanzer  Â·  3Comments