Closed maorefaeli closed 5 years ago
You can currently get the results you want by using getEntries()
to get an array of all the [key, value]
tuples, then sorting the entries however you want before mapping them to JSX Elements:
$enum(Log)
.getEntries()
.sort((lhs, rhs) => lhs[1] - rhs[1])
.map(([key, value]) => (<option key={value}>{key}</option>);
I will not be adding any extra params to the $enum()
function to control how the EnumWrapper
instance is initialized, because that will lead to confusion and bugs if you call $enum()
on the same enum multiple times throughout your code. Only the first call will initialize the instance, and all subsequent calls return a cached instance. You would have to find all calls to $enum()
for a given enum and update them all to use the same params to guarantee the EnumWrapper
instance is initialized as you expect, which is a bad design.
I will, however, consider changing the hard-coded sort order to be based on value rather than key. The sort order is not intended to be meaningful. It is only intended to guarantee consistency across JS implementations, since there is no guaranteed order of iteration over keys of the original enum object. But I do agree that it is more likely that sorting by value will be more meaningful than sorting by key. I only sorted by key because it was the simplest and most efficient implementation to guarantee consistent order.
I will also consider adding a global setting to disable sorting. This would be useful if you know that object properties/keys are always iterated in the order in which they were defined within the environments that you will run your code (very common, but not guaranteed by ECMAScript specs). This would retain the exact order of the enum's definition, which is probably the most meaningful order.
Thanks for your reply,
I get what you say about the extra parameter to $enum()
.
I don't know if a global setting will be the best solution because different enums have different meanings, and therefore different sorting purposes.
Maybe a sorting parameter to the map
, keys
, values
, etc. ?
different enums have different meanings, and therefore different sorting purposes.
Exactly why I can't really include a solution that works for everyone :)
I can only choose the default sort order that makes the most sense in the largest number of use cases, and provide tools to let you do whatever you want with the result afterward.
My options for default sort order are:
Option 3 cannot be guaranteed to be consistent across all JS implementations, so I don't want it to be the default. In environments where the order of definition of properties is preserved, I think this is most commonly the most meaningful order (developers often list enum definitions in some logical order), which is the only reason I'm considering making it an optional global setting.
Between options 1 and 2, I think 2 may be more likely to be meaningful (at least for numeric enums). I'm really not sure how to go about determining whether this is true, because it depends on having knowledge about how most people use enums. I can only assume based on how I use enums, and how I've seen enums used in a limited number of projects.
Regardless of the default sort order, tools are already available for you to sort however you want, via getEntries().sort()
.
Maybe a sorting parameter to the map, keys, values, etc. ?
I'd rather not complicate all those methods. Some of them are quite optimized right now because of assumptions of immutability, etc. It also wouldn't be very intuitive for all of those methods to accept a comparator.
I think the most reasonable improvement over existing functionality is to implement a sort()
method directly on EnumWrapper
that creates a new lightweight copy/view of the original EnumWrapper
, but in terms of the specified sort order. This would be purely for increased convenience. The challenge is making some decisions on how to implement this, what kinds of use cases to optimize for, etc.
Consider everything you said,
I'm considering making it an optional global setting
sounds like the best solution.
One could set that flag for its most common use case and use getEntries().sort()
for the others.
implement a
sort()
method directly onEnumWrapper
would be nice, but like you said, only on increased convenience over the existing solution :)
After some more research, I've decided that the next major version of ts-enum-util
aim to retain the exact order of the original enum definition by relying on ES6's specification of Object.getOwnPropertyNames
and the de facto standard of key iteration in all modern browsers.
The subtle difference between some browser implementations of key iteration order is a matter of whether creation order is retained for ALL kinds of keys, or does it follow the ES6 Object.getOwnPropertyNames
specification for iterating numeric keys in numeric order first, followed by string keys in order of creation, then symbol keys in order of creation.
Since I only care about the string keys (I explicitly ignore numeric reverse lookup keys that TypeScript generates for numeric enums), then I think it's safe for me to rely on Object.getOwnPropertyNames
to give me the keys in the order they were originally defined in the enum. Even if a polyfill is used in some environment that doesn't have native support for Object.getOwnPropertyNames
, it will be implemented in terms of either Object.keys
or for/in iteration, which is almost guaranteed to follow de facto standards of at least retaining relative creation order of the string keys I care about.
I might even implement a simplified polyfill for Object.getOwnPropertyNames
so that this doesn't depend on a an external polyfill.
If you want the new "original defined order" behavior, check out the latest alpha release ("alpha" tag on npm). Other than the change in sort order, the only other breaking change is that TypeScript 2.9 is now the minimum supported version.
The biggest change in the next major release is that I have taken the functionality of ts-string-visitor, expanded it to handle number literals (and therefore numeric enums), and merged it into ts-enum-util
as $enum.visitValue()
and $enum.mapValue()
. The code is all done and tested. Updating the README is the hard part that I still have to do before releasing it.
Version 4.0.0 is now released, which nearly guarantees that the original defined order of the enum will be retained. This new default sort order should be more useful in most cases.
Motivation: In numerous scenarios, the order of the values is more important than lexicographical keys. for example:
The
select
will have the options ordereddebug, error, info, warning
which is harder to understand thandebug, info, warning, eror
.Maybe add something like
$enum(Log, true)
to order by value? or passing comparable? Thanks