2020-12-14
1057
#typescript
Paul Cowan
30575
Dec 14, 2020 ⋅ 3 min read

Put the TypeScript enums and Booleans away

Paul Cowan Contract software developer.

Recent posts:

Offline-first frontend apps in 2025: IndexedDB and SQLite in the browser and beyond

The web has always had an uneasy relationship with connectivity. Most applications are designed as if the network will be […]

Alexander Godwin
Nov 18, 2025 ⋅ 11 min read
Real-Time AI In Next.js How To Stream Responses With The Vercel AI SDK

Real-time AI in Next.js: How to stream responses with the Vercel AI SDK

Streaming AI responses is one of the easiest ways to improve UX. Here’s how to implement it in a Next.js app using the Vercel AI SDK—typing effect, reasoning, and all.

Elijah Asaolu
Nov 17, 2025 ⋅ 9 min read
How to fix React routing loopholes with the React Router Middleware

How to fix React routing loopholes with the React Router Middleware

Learn how React Router’s Middleware API fixes leaky redirects and redundant data fetching in protected routes.

Ikeh Akinyemi
Nov 13, 2025 ⋅ 3 min read
How I used Mastra to build a prize-winning RAG agent

How I used Mastra to build a prize-winning RAG agent

A developer’s retrospective on creating an AI video transcription agent with Mastra, an open-source TypeScript framework for building AI agents.

Chinwike Maduabuchi
Nov 13, 2025 ⋅ 12 min read
View all posts

8 Replies to "Put the TypeScript enums and Booleans away"

  1. What about when you have a union of strings and you have strings fed into your app that implicitly acquire this string union but then you need to change one of the string values in your union?

    Now you get rogue errors from strings that no longer match the spec all throughout your app.

  2. You can also do algebraic data types and exhaustive pattern matching with enum values.

    {type:MyEnum.a} | {type:MyEnum.b} will work the same.

    I personally often prefer enums because you can search for usage of values, and rename them easily.

  3. Yes, I’m curious to know why the author did not conclude with that solution which is essentially the best of both world. As you said it’s much better for searching and refactoring and it’s the same behavior as using plain strings.

  4. It boils down to enums being references and strings being values. You can navigate through your code easily using enums. You can easily refactor them using code editor features like “rename symbol”. This for example does not work with strings. I’ve tested this with the example code you’ve linked in your comment.

    Also, you can define the value of “UnionSwitch[‘kind’]” with a simple variable: “const on = ‘on'” and use it inside an object of type “UnionSwitch”. This “on” variable however cannot be found using “go to references”. It’s like a blind spot. This however is not a problem with enums – unless you really want it to be.

  5. I think all of the replies so far have missed the point. I also mentioned booleans as a bad way of modelling state.

    The point is not about the string values and being able to refactor them, that seems hardly worthy of a post.

    The point is that enums like this

    enum Auth {
    unauthenticated = ‘unauthenticated’,
    authenticated = ‘authenticate,
    }

    or

    const isAuthenticated = true;
    const authenticated = false;

    are bad ways of modelling state and discriminated unions where the typescript compiler can type narrow on a string field is far superior:

    type Auth =
    | {
    kind: “UNAUTHORISED”;
    context: {
    isLoading: false
    };
    }
    | {
    kind: “AUTHENTICATING”;
    context: {
    isLoading: true;
    };
    }

    Unfortunately everyone seems fixated on the string values….that is a small point.

  6. all the replies so far have missed the point of the post and seem fixated on the string values, and the ease of refactoring string values.

    The point of the post is that booleans and enums are bad ways of modelling state.

    Modelling state is nothing to do with refactoring string values. That is not exactly worthy of a post.

    Discriminated unions are far superior and the example in the post has an authenticated state and the compiler only allows access to the authtoken field when it has type narrowed when the discriminator is of `kind: ‘Authenticated`

    refactoring string values is not exactly something to get excited about.

  7. I know what you want to say. And I agree, that discriminated unions are a far better idea to model the state than a simple interface. But you take two steps at the same time. You replace the initial state type or interface with a discriminated union AND you replace booleans or enums with a string. You make it seem that both go hand in hand or are the same thing, but those things are unrelated. I (and also others) suggest to only take the first step: Use DUs as the type of the state object but keep (mainly) enums for its properties:

    enum Auth { authenticated; unauthenticated }

    type AuthState =
    | { auth: Auth.unauthenticated }
    | { auth: Auth.authenticated, user: { username: string } }

    Olivier already made that example in a simpler form. Then you asked what this would give one aside from more code. And my answer was: Better flexibility and code analysis. And this is why it is – how Gabriel put it – the best of both worlds.

    So, yes. It is a small point. It is because we don’t fully disagree with what you say. We just want to provide a little improvement to your idea. The thing is, this small point is also the big message of the headline of this post.

Leave a Reply

Would you be interested in joining LogRocket's developer community?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now