How to use TypeScript Enums and why not to, maybe

Sdílet
Vložit
  • čas přidán 21. 08. 2022
  • More details on TypeScript Enums: shaky.sh/ts-bit-flags/
    Do you have a good use case for enums? I'd love to hear about it in the comments!
    #typescript #enum
  • Věda a technologie

Komentáře • 56

  • @po9968
    @po9968 Před rokem +4

    Do you have the same reluctance with classes ? Given that they have the same characteristics than enum, to be both value and type ?

    • @andrew-burgess
      @andrew-burgess  Před rokem +8

      hmm, good question! I don't typically use classes much, but if that's the pattern you're using, I think classes are fine. The nice thing about classes is that they are a type and a value in BOTH TypeScript and JavaScript, so the behaviour is pretty consistent: that is, you can do `myObj instanceof MyClass` in both TS & JS.
      One thing to keep in mind is that JavaScript doesn't (yet) have private properties within classes, so any private properties in your TypeScript classes will be normally-accessible properties once transpiled to JavaScript.
      edit: put together some quick examples here: shaky.sh/ts-private-properties/

    • @po9968
      @po9968 Před rokem +2

      Thanks to share your thoughts, Andrew !
      Actually, I have difficulty to find a good use case for real classes. I use Java for a long time and JS for 5 years. It seems unnatural in TS, in part, because TS only need the shape of the object to consider the type.
      Whatever, you have a point to mention the instanceOf operator available in both TS and JS worlds, pretty consistent indeed.
      Nice article to private properties trick.

    • @igorswies5913
      @igorswies5913 Před rokem +5

      In JS and TS you can use closures instead of classes and that way you don't need to use the "this" keyword

  • @arnthorsnaer
    @arnthorsnaer Před rokem +12

    I’ve used enums to great effect in my project. In regards to accept user input and start using it directly in relation to a string enum, I think that in itself is a vad practice and you should always sanitize and qualify the input anyway to see if it matches the enum. So I actually like TS insistance on making devs explicitly use the enum instead of passing in the string.

  • @juniomilnovecientos
    @juniomilnovecientos Před 2 měsíci

    your alternative became even better with typescript declaration merging which allows us to use the same name for the value and type

  • @zavarka2
    @zavarka2 Před rokem +2

    Such a clear and thorough explanation of the enums and the alternative! I finally get it. Thank you, Andrew!

  • @ozzyfromspace
    @ozzyfromspace Před rokem

    First video and I NEED to subscribe. Awesome discussion, Andrew! I look forward to learning from you and suggesting your channel to other devs.

  • @Metruzanca
    @Metruzanca Před rokem +4

    The last example is what I ended up doing myself many times. Super frustrating to work with enums. Sometimes they work fine, other times you just end up regretting using them.

  • @rikuswiehahn8923
    @rikuswiehahn8923 Před rokem

    This "as const" technique is 🔥 don't know how I didn't come across it earlier, thanks for sharing!

  • @33v4.
    @33v4. Před rokem +1

    I look forward to seeing your channel growing my fren! awesome content

  • @e2e23e
    @e2e23e Před rokem

    Very clear explanation. Thanks for sharing.

  • @ejazmuneeb
    @ejazmuneeb Před rokem +1

    I don't subscribe a lot but i am subscribed to you hats off to Andrew great tutorial

  • @developerfriendly
    @developerfriendly Před rokem

    great tutorial, thanks!

  • @wojciechtomczyk4020
    @wojciechtomczyk4020 Před rokem

    Great video!
    After watching I started thinking, and this is the result:
    export type Enum = T[keyof T];
    const ABC = {
    A: 'a',
    B: 'b',
    C: 'c'
    } as const;
    let X: Enum = ABC.B;

    • @dimitargetsov9690
      @dimitargetsov9690 Před rokem

      With my full respect :
      I removed "extends Object" from and it still works.
      Any idea why?

  • @joostschuur
    @joostschuur Před rokem +3

    Still new to TypeScript, but at this point, why not just set the type for PostState as a union of strings ("DRAFT" | "SCHEDULED" | "PUBLISHED")? There's a lot of mental overhead for me to process what you used in the end.
    You still get auto completion. Anything else this doesn't get you? Or is it purely the look of raw strings vs. the more contextual syntax that repeats the PostState part in PostState.Draft e.g.?

    • @kbitgood
      @kbitgood Před rokem +1

      You're absolutely right. You don't get anything more than the PostState.Draft object notation vs the "DRAFT" string literal. To me this is purely a code aesthetic choice. When self documenting code is important, especially with multiple developers writing library code with the same enum, then Andrews pattern is nice. But its often overkill.

  • @ejazmuneeb
    @ejazmuneeb Před rokem

    🤯🤯Shocked to see such low subs? absolute great content.

  • @roynilsson1382
    @roynilsson1382 Před rokem

    Awesome video. helped me allot.

  • @moodynoob
    @moodynoob Před rokem +4

    Are there any good use cases for enums beyond when you essentially want named numbers? I used to use them liberally but then found just using unions of strings way more ergonomic.

    • @andrew-burgess
      @andrew-burgess  Před rokem +4

      I haven't come across any cases where a unions of strings doesn't make sense.

    • @igorswies5913
      @igorswies5913 Před rokem +1

      @@andrew-burgess renaming

    • @andrew-burgess
      @andrew-burgess  Před rokem

      @@igorswies5913 hmm, can you say more? not sure I follow.

    • @igorswies5913
      @igorswies5913 Před rokem +2

      @@andrew-burgess I don't think you can rename a string from a union using F2 and have it be updated everywhere, can you?

    • @andrew-burgess
      @andrew-burgess  Před rokem +2

      @@igorswies5913 Oooh, gotcha! Yeah, that's a good example!
      The best you get in that case is that after you update the union, the type checker will tell you all the places that no longer match the union. But you'll have to update them manually :(

  • @catwhisperer911
    @catwhisperer911 Před 9 měsíci

    They are the Devil incarnate! LOL I never use them. Thanks for sharing.

  • @user-cb7kd8mr2d
    @user-cb7kd8mr2d Před 9 měsíci

    I use a very similar solution, but instead of "as const", I wrap my object literal with Object.freeze, which has the same TypeScript benefit of "as const" and also protects your object at runtime from someone making changes to it.

  • @LukaLightBringer
    @LukaLightBringer Před rokem +1

    In which scenario would using the same name for the type as the variable be a problem? Surely the type names don't have any relevance on the variable names in typescript, isn't the language always lexicographically disambiguous in whether you're refering to a type or a variable?

    • @vaap
      @vaap Před rokem

      as far as im aware, yes. i do that all the time lol. very useful as an export

  • @2tvtv
    @2tvtv Před rokem

    🙏🙏

  • @chunkwanchan5503
    @chunkwanchan5503 Před rokem

    the best!

  • @tmbarral664
    @tmbarral664 Před rokem

    @11:47 ok, it works......but.... I want to forbid the use of string here, I wish to force the use of PostState.Draft as a sngle source of truth. As a matter of fact, I was using enum and not union for that very reason.
    Any suggestions ?

  • @officemax3977
    @officemax3977 Před rokem

    nice blooper at the end there :D

  • @dixztube
    @dixztube Před rokem

    Go kinda avoids enums I use them in strapi but generally kinda keep away from em

    • @andrew-burgess
      @andrew-burgess  Před rokem +1

      It's been a while since I dabbled in Go! But Rust enums are absolutely THE BEST. I think the union type + exhaustive switch pattern in TypeScript took a lot of inspiration from Rust enums.

  • @jasonrooney1368
    @jasonrooney1368 Před rokem

    I ran into an interesting problem with this pattern.
    If you want to use an enum-like for a generic argument, an actual enum will work, but the as const version will not.
    If you try to pass Post, it will complain that PostStateType is not a known namespace. However, you can still use the literal value Post.
    On the other hand, with enums, you can use it directly as a generic argument i.e. Post

    • @fahadahaf
      @fahadahaf Před rokem

      You can pass `Post` instead and it would work, You can even make it nicer by making a type alias for `type X = typeof PostState` and now you can do it like this `Post` if you prefer. the only downside that you can't use the dot operator; so you have to do `X['Draft']` instead of `X.Draft`.

    • @fahadahaf
      @fahadahaf Před rokem

      ```
      type PostStateK = typeof PostState
      type PostStateV = PostStateK[keyof PostStateK]
      interface BetterPost {
      id: number
      state: State
      }
      const y: BetterPost = {
      id: 2,
      state: 'DRAFT'
      }
      ```

  • @markokraljevic1590
    @markokraljevic1590 Před rokem

    why is there no link from the code?

  • @ransomecode
    @ransomecode Před rokem +2

    Yes you shouldn't use them; JavaScript Symbols exist for that reason (according to MDN)
    for instance:
    ```
    const Colors = {
    RED: Symbol("❤️"),
    BLUE: Symbol("💙"),
    GREEN: Symbol("💚")
    }
    ```

  • @tvujtatata
    @tvujtatata Před rokem +1

    Its funny how TypeScript refuses to add some QoL because it would affect the resulting JS code and then enums exist lol.

  • @kbitgood
    @kbitgood Před rokem

    I think you can absolutely have both the constant and the type have the same name "PostState". Since one is a value and one is a type they won't collide. Typescript knows when you are using it as a value and when you're using it as a type. And it also gives the exact same DevX as Enums because an enum is both a type and a value.

  • @ginger-viking
    @ginger-viking Před rokem +4

    Good video, annoying music. Subscribed.

    • @andrew-burgess
      @andrew-burgess  Před rokem +2

      Thanks! Yeah, I’ve gotten feedback on the music, and have been (I hope) improving that.

  • @Chris-jm2gx
    @Chris-jm2gx Před rokem +1

    why even bother with enums or object as consts if you can just use union types of specific values?

    • @rutabega306
      @rutabega306 Před 2 měsíci

      Refactoring is a bit easier if you can search for the enum/object name

  • @evccyr
    @evccyr Před 2 měsíci

    Honestly typescript doesn't really give any feel of a strongly typed language. It also adds to the complexity.

    • @andrew-burgess
      @andrew-burgess  Před 2 měsíci

      Ooh, that's a take I haven't heard before: that TS isn't strongly-typed. Say more?

  • @mahadevovnl
    @mahadevovnl Před rokem

    I think enums are a mistake in TypeScript. It should be removed. Just like "interface" should be removed and its (very few) unique features should be included in "type". Unfortunately, the TypeScript group is too careful too often. Just remove it in the next major release. Most people won't care because most people aren't using it.

  • @Threnode
    @Threnode Před rokem

    5:00-5:45 Why the hell would you use numbers anyway if you can use human-readable form? Why purposely add obscurity to your own code...
    7:00-8:27 Using strings is prone to typos and when you need to change the value, you have to do it in only one place. If you need to change the reference, you always know where it comes from. When you have an object that holds your constant values, why would you type in a value itself, when you can refer to that object? If you want to do otherwise, why to create enum at all?
    And what is wrong with importing from library? Isn't it a good thing if a library provides you with a more flexible (I mean, that can be used as a type and value) contract of using it?
    Imo, what you said about enums should be presented not as flaws, but as peculiarities. One should be aware of them, true.

  • @rex_melynas
    @rex_melynas Před rokem

    Can't we just get a lesson from C++ and have enum classes ?
    enum class State {
    Draft,
    Scheduled,
    Published,
    }
    // Nope
    const x: State = 0; // TS: Error, invalid value for State, should be `State.Draft`, `State.Scheduled` or `State.Published`
    // Still Nope
    const x: State = 3; // TS: Error, invalid value for State, should be `State.Draft`, `State.Scheduled` or `State.Published`
    // Nope Again
    const x: State = "Draft"; // TS: Error, invalid value for State, should be `State.Draft`, `State.Scheduled` or `State.Published`
    // Yep
    const a: State = State.Draft;
    const b: State = 1 as State; // Explicit cast
    const c: State = 5 as State; // Will work, but you shouldn't use this.

    • @andrew-burgess
      @andrew-burgess  Před rokem +3

      Yeah, other languages do it so much better. I’d love rust-style Enums in TS, where you can store values and do matching (you can kinda get this pattern with an exhaustive switch and union type in TS)