There has been a lot of excitement around Typescript lately. There’s the Go rewrite to look forward to. But even without the wait, Node.js has finally added native support for Typescript syntax. An interesting detail about this native support is that it can only remove typescript syntax, it cannot transform the syntax itself. This is not new, as other projects have implemented Typescript compilers that work similarly and replace the type annotations with whitespace, making line and column numbers just work even after transformation. This is to say nothing about the performance benefits of such a simple transformation.
The Typescript team itself has seen value in this and has shipped a new --erasable-syntax-only
flag,
that disallows certain Typescript features that are not compatible with such a transformation. Fortunately,
none of these incompatible features are all that important to begin with and are usually just syntax conveniences
that helps write less code. There is one exception, however, enums
.
#Syntax Proposal
Many, including myself, would argue that Typescript enums are a mess and it’s better to just use union types instead.
However, enums
are a useful feature and this is a great opportunity to get them right. Here’s my proposal for
how it could work:
Typescript already supports as const
and as SomeType
to annotate javascript expressions. This same syntax could
be extended to support simple object expressions as a way to define enums
. This new enum would be a plain object
only and would not have any of the other fancy runtime features that Typescript enums do today. enum
s should purely
be a typesystem feature.
Of course, enums should support different kinds of backing values.
Typescript could validate that all values within an enum are the same primitive type.
The usage with switch
statements would work as expected:
#OptionSets
This is also an opportunity to introduce a new feature to typescript: Option Sets. It is sometimes useful to create a type where you can have more than a single value at a time. This is usually done by using bitshifting and bitwise OR, but there has been no typesystem support for this so far.
By enforcing certain patterns, this could be made possible in Typescript:
Typescript would enforce that each of the individual options is expressed as a bitshift expression with no overlaps.
Additional “convenience” value can be included as getter functions:
The slightly more interesting question would be how to use these optionSets. Typescript could treat optionSets distinctly from numbers and disallow arbitrary mathematical expressions except those that are relevant, such as:
It would only be valud to |
or &
with another value of the same type
and comparison against 0
.
#Enums with Data?
Now, getting into the more holy grail situation of enums, it would great to support enums with data. Again, this is already possible with union types, but could there be a way to add first class support at the typesystem level that could help simplify things and improve performance in large projects?
Expressing such a type seems possible.
However, when it comes to actually using such a type and enforcing exhaustiveness, things get
a bit more complicated. Ideally, we’d get native support
for match
expressions in Javascript and Typescript could lean on that.
However, while we wait for the pattern-matching
proposal to gain traction, we could
add an additional constraint to enums with data and require all possible values to be
objects with a consistent key
.
This would mean that something like this would be invalid:
Ideally, the keyname should be configurable, and Typescript should be able to
infer that in this case the key is type
, but you should be able to use any
consistent key that you want.
#A compromise?
The enums with data proposal is definitely a lot more complex that simply introducing a new simple syntax for enums. Perhaps we could compromise in the meantime and settle on something simpler for enums with data in the meantime?
Where Typescript ships a new utility type EnumWithData<EnumKey, KeyName>
which would enforce
that all possible values of EnumKey
are objects with a KeyName
property.
#Conclusion
The new tools and implementations of Typescript that simply erase types is a great step forward. It lets us move in a direction that would be compatible with the types as comments proposal.
But we should settle for losing out on useful features as we move into this new world. We should come up with new syntax solutions that help us bring along useful typesystem features without adding new syntax. And while we’re at it, we should also fix the major mistakes in Tyepscript such as how enums behave today!