Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> 1. Avoid Enums

What? This is IMO bad advice. Having a sum type is quite handy for general type-checking, at least insofar as the type truly is an enumerated type (i.e. all possible values are known at design-time). There have been times when TypeScript enums have been indispensable to me when declaring the external interface to some client-facing API. Whatever the API boundary is, a sum type is useful.

Also, TypeScript gives general intersection types, which is quite rare among its peers. (What I wouldn't give some days for mypy to have intersection types, or bivariant functions, or conditional types, or ...)

The only other impetus for this post I can imagine is some weird desire to see typescript as a strictly separate layer above JavaScript that "could be removed" if we wanted it to be. I suppose that was the project's original telos, but today the abstraction is leaky in a few places. I'm a world where JSX is common and radically departs from what would be considered normal JS, I don't see a problem with TypeScript being leaky here and there. Hell, I'd prefer TS to be leakier and add opt-in runtime checking (i.e. code gen), because it would make my life easier in certain instances.



Unfortunately TypeScript's enums have various shortcomings compared to powerful sum types in languages like Rust:

- https://stackoverflow.com/questions/40275832/typescript-has-...

- https://github.com/microsoft/TypeScript/issues/32690

In a TS codebase I'm currently working on, we have the policy of never using "plain" TS enums. Instead, we have a tool that generates our own enum objects using a schema and a generator script for the cases where we want "rich" enums. For other use cases, we use string unions a lot (in combination with a helper function that allows exhaustive matching).


Rust can't do your second example yet either. Enum variants are not distinct types. It's a commonly requested feature though so hopefully soon...


Based on how two of the four points key into it, I think the author is stuck using a tool in their tool chain that doesn't support TypeScript and has been bitten by that tool doing something Byzantine in response to TypeScript-generated code.

That's a problem a lot of developers won't have. I've covered a lot of ground without ever finding a tool that either hasn't been retrofit to support TypeScript or that has issues that are tickled by TypeScript generated code. My blunt recommendation if somebody hits that problem is to find a better tool.


What are the advantages of enums over a string literal union? I can only see disadvantages.


Unfortunately, neither (string) enums nor string literal unions are supersets of each other when it comes to functionality. But, IMO, string-only enums are generally better.

You can't test if a given string is an element of a union without writing a custom helper and/or allocating a runtime array of the values.

On the other hand, if you don't need to test unknown strings, then union types disappear at compile time, whereas enums are compiled to real, runtime, objects.

Enums don't look like naked strings in the code. Frankly, it's just nicer on my brain to see `return Color.Red` than `return "red"` and wonder if "red" is just some random text or if it has semantic meaning. Hopefully your IDE is smart enough to take you to where "red" is defined as part of a union type when you want to see other options. Granted- the most popular editors ARE smart enough to do that, but that doesn't help when just reading code with my eyes instead of my hands, or in patches/diffs.


In some cases you can use it to define string arguments to an external library. Maybe table names to an ORM or a well-known file path. This helps because you get autocomplete from typing `MyEnum.` and seeing options, even though the external function takes a plain string.


All of that is possible with a string literal union though, surely?


It's not possible to get the autocomplete unless the function/method you're calling takes a union. Many libraries can't do that because they need to be flexible in what they receive. So yeah, you can define a union, but editors don't have the context to know your union applies to the call.


If you have to change one of the underlying values, you only need to change it in one place. Of course, you could just use constants, but then you’ll just have a const enum with extra steps.


The TypeScript ecosystem is bigger than just the official compiler, though. Many projects use alternative compilers like esbuild or @babel/preset-typescript for their main pipeline and only use the official TypeScript compiler as a typechecker (with `--noEmit`, during CI).

It's true that enums are harder to support for alternative compilers. Especially `const enum` seems to be harder.


> It's true that enums are harder to support for alternative compilers.

As long as it is supported — and at least esbuild does, who cares (as a user). Should I start avoiding every JS feature that is hard to implement in alternative JS runtimes?


I don't know why you should care if it doesn't affect you.

At least TypeScript cares enough to have added the `isolatedModules` and the `preserveValueImports` flags:

https://www.typescriptlang.org/tsconfig#isolatedModules

https://www.typescriptlang.org/tsconfig#preserveValueImports


yes, we should also restrict every C++ feature to what Borland Turbo C++ 3 supports too, since there are still school that teach that making it part of the C++ ecosystem.

Actually, as Amish communities are part of the human ecosystem, maybe we should also restrict anything we build in the real world to something that can be useful to the Amish and stop building anything requiring a power grid ?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: