TypeScript Enums are TERRIBLE. Here's Why.

แชร์
ฝัง
  • เผยแพร่เมื่อ 29 ก.ย. 2024

ความคิดเห็น • 275

  • @MichiganTypeScript
    @MichiganTypeScript  ปีที่แล้ว +1

    Josh Goldberg (of typescript-eslint) came to Michigan and did a response to this video: "Enums are MISUNDERSTOOD (not terrible)". Check it out: th-cam.com/video/XTXPKbPcvl4/w-d-xo.html

  • @cyphern
    @cyphern ปีที่แล้ว +156

    @3:25 I'm not commenting on whether this was a good design decision, but here's the reason that any number is allowed: An enum who's values are numbers is sometimes used for bit masks. For example, your enum might be defined as {foo = 1; bar = 2; baz = 4}. Or in binary, that's 0001, 0010, and 0100. But then these can be combined to say that something which is both foo and bar is a 3 (0011), something which is both foo and baz is 5 (0101) and something which is all three is 7 (0111). If this is to be supported, numbers outside the explicitly defined ones need to be permitted. Perhaps with the modern advances to TS they could efficiently calculate a union of all the possible combinations, but it was implemented with a simpler solution: allow all numbers.

    • @MichaelMolisani
      @MichaelMolisani ปีที่แล้ว +9

      Good point. TypeScript uses enums in its own codebase quite extensively, but almost exclusively as bit flags rather than the "numeric enum" most end up using these for.

    • @cody83462
      @cody83462 ปีที่แล้ว +18

      Using enums for bit masks totally defeats the purpose of enums in the first place. When doing arithmetics with enums you actually want numbers. You lose type safety completely when allowing this.

    • @AkioJunichiro
      @AkioJunichiro ปีที่แล้ว +2

      @@cody83462 I don't know what you are talking about but in other language using enum as a mask is a pretty common thing and you are not loosing the type safety either.

    • @cody83462
      @cody83462 ปีที่แล้ว +2

      @@AkioJunichiro If you bitwise OR two enum values and get a result that is not in the enum, this is either not type safe or you just get an integer. Does not make too much sense. But of course you can do it in some languages. Bad design is also a common thing, so just do it.

    • @natrixnatrix
      @natrixnatrix ปีที่แล้ว +3

      @@cody83462 The point of an enum is to have an integer like type where the underlying value specifically should not be relied upon. It's the same as why you cannot do arithmetic on a void pointer in c. When you are using an enum you are essentially telling other people that the value is not safe to for example store in a database.

  • @asimpleguy2730
    @asimpleguy2730 ปีที่แล้ว +8

    I still don't get how object are better than enums with specified string values.
    1. The object typing syntax is more verbose, and it allows the method to accept a string, a thing i would argue is not good since if i rename the the value inside the enum, the method is not going to work anymore.
    2. The argument of "yeah it works but you are using a subset of what the enum is, so that's bad" doesn't make any sense

    • @highwind81
      @highwind81 ปีที่แล้ว

      The language and tools should serve me not the other way around. If I have to constantly think about which subset of a feature I should use, then we should just go back to the "JavaScript: the good parts" days. The whole point of TypeScript is to unload that cognitive overhead but enum goes against that idea.

    • @asimpleguy2730
      @asimpleguy2730 ปีที่แล้ว

      @@highwind81 I personally disagree. We never left the "javascript the good parts" days IMO.
      If you think about it, best practices are kind of a subset of how you could use a language/framework/tool. We are constantly selecting between what the best way to implement stuff is, simply for the reason that there are multiples way to implement stuff.
      Think about how many ways you have to iterate through an array, and in that, Typescript will not help you in any way decide if you want to use map or a for each.
      That's why i think the argument "i shouldn't use a subset" is nonsense.

    • @ibgib
      @ibgib ปีที่แล้ว

      I'm thinking this would inevitably come down to a per use case analysis, but could you give an example of a good time to rename a value "inside" an enum?
      I personally prefer the flexibility to use the enum-like syntax as needed and the string literals other times, depending on context (in code) and ultimately to maximize readability. For example if I had a function called `foo` I would like to pass in `AuthMethod.voice` as one of the args, but if I had `fooAuthMethod` I might prefer `fooAuthMethod("voice")`. And I absolutely recoil at thinking of changing an enum value, but there are probably good use cases for this and I am probably over-reacting.
      Note: I often would actually have a single object parameter so I could use named args and thus oftentimes I use the string literal, e.g. `foo({authMethod: "voice"})`.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      one argument I hear a lot from people is they don't like the runtime artifacts that enums produce. at least objects are well understood and simple.

  • @0xyz
    @0xyz ปีที่แล้ว +14

    Great video, can the editor please keep the screen on the code editor and stop the switching please

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +6

      That's super great feedback! We'll look into more layouts that keep the code visible, but also we'll try to reduce switching away from the code in the future. thanks!

  • @okayestdev5237
    @okayestdev5237 ปีที่แล้ว +9

    I'd recommend to avoid using the integer enums (not initializing them with values). Use the string enum aproach. They're fantastic.

  • @themikeholm
    @themikeholm ปีที่แล้ว +2

    I don't really see how using a POJO with an overridden type is worse than using an enum with strings. It's constrained? I would love some more explanation on this point.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I think people prefer it because it's more "obvious" what the runtime artifact will be

  • @anon_y_mousse
    @anon_y_mousse ปีที่แล้ว

    I doubt anyone will see this now, but this illustrates why enums should be treated differently. Consider a language like C where there's really no language enforcement to require enums to be a certain way, but most compilers, at least good ones, will have warnings or errors or both that you can enable pertaining to checking them at compile time. If you know what you're doing, you don't even need a warning, let alone an error, but for those that are learning, you can enable it.
    However, therein lies a problem, as others have stated, they are often used as bit flags and that defies the closed set nature that quite a few want to use them as. I think the best thing a language could do with regard to handling enums and typing them is to have a type constrained addendum to the description for an enumerated type. For instance, if they're going to be used for bit flags, have something like enum as the type and for actually constrained value types use something like enum.
    Obviously, I don't use TypeScript in my job, and don't even really know it beyond what correlates with JavaScript. Mostly I've been watching these videos to determine if I want to take my knowledge a step further and what I've seen has told me that I wouldn't want to use it to write anything serious. I see a lot of problems with modern day web languages, and quite frankly I'd like to start from scratch in that regard. A lot of what Java did shouldn't have been done and certainly shouldn't have been copied yet nearly every web language since has copied these things. I see a lot of this with regards to markup languages like HTML as well. We really need to wipe the slate clean and start from scratch, but it won't happen and we all know why. It's just too much work, too much that would need to be transitioned and too much already working code exists that to rewrite it would be an enormous undertaking that no one would want to spend money on.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      _I see you, I see you_.
      for what it's worth, I found this to be a really valuable bit of insight. it's a great point you make.. the one about copying thigns from language to language where it doesn't make sense.
      Hopefully the content on this channel won't scare you away, but I will say that it's a bit unusual in the sense that it's got a lot more advanced topics and not as many lower and beginner topics. I'd recommend to you and anyone else to take a look at Matt Pocock's work (Total TypeScript) if you're wanting to know more (but, like, in a more controlled and curated fashion).
      Everything Matt does is great.

    • @anon_y_mousse
      @anon_y_mousse ปีที่แล้ว

      @@MichiganTypeScript I suppose I'd need to see how it would work with a real project. If you had a favorite open source project that predominately used TypeScript as the language of implementation, that would probably give me a better feel of it as a language.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      @@anon_y_mousse sure: mui (previously known as material-ui) is a pretty clean codebase. that could be a nice place to look

    • @anon_y_mousse
      @anon_y_mousse ปีที่แล้ว

      @@MichiganTypeScript Thanks, I'll check it out.

  • @user-cd6vy2jg6f
    @user-cd6vy2jg6f ปีที่แล้ว +1

    2:35 “I have no idea why there’s probably a reason for it”
    You really shouldn’t give a presentation statement / opinion on something you don’t understand.
    First rule is know the thing you’re speaking on

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I hear what you're saying, but just to say it out loud at Michigan TypeScript we really encourage a talk like this where the presenter may not know every nuisance. there's a part of the events that unfortunately you can't see on the videos: which is that we all go out to get tacos or drinks or whatever afterwards and often talk about exactly this kind of thing. thanks for watching

  • @The14Some1
    @The14Some1 10 หลายเดือนก่อน

    there is a thing as const enums. Why didn't you cover it here?

    • @MichiganTypeScript
      @MichiganTypeScript  10 หลายเดือนก่อน

      check out the follow-up to this talk by Josh Goldberg. if memory serves: he covers it there

  • @ibgib
    @ibgib ปีที่แล้ว +1

    Loved the video! I am most excited about the code you show at the very end with the new `satisfies` keyword. If I could just force myself to learn it I might break out of my habit formed in the early days of TS before there were enums and before the `keyof` operator...My VsCodeVim habit (I'm not that hardcore!) enables me to lazily parse the union type and construct the constant, where I use the `as AuthMethod` technique. Duplicated code, I know - but very readable for my old eyes!

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      I have about 30 things I do that are just "but I've been doing them that way for a long time" coding habits, don't worry, you're in densely populated company

    • @dealloc
      @dealloc ปีที่แล้ว

      But `as` type assertion is a footgun, because it changes the type underneath you and you lose the type safety that satisfies provides.
      The alternative to satisfies, if you use older TypeScript version, would be to use an identity function with a generic as a constraint: `const foo = (value: T) => value;` where Foo would be your type. Then wrap any value within it like `const someFoo = foo({ a: 1, b: 2 })`. and `typeof someFoo` will now be a narrowed type of Foo, that satisfies its constraints. You also get the type safety within the declaration, since it conforms to Foo.
      Of course this adds a neglible overhead in terms of runtime, but rather cumbersome boilerplate, which is why the `satisifies` keyword was introduced. It removes the need to wrap every single thing in a custom function just to get a proper narrowed type.

  • @adamhenriksson6007
    @adamhenriksson6007 ปีที่แล้ว +1

    Bro have you seen python enums? They really make me cry everytime i even consider using them.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I haven't, but I cry anyway when I see python. rip: me

    • @adamhenriksson6007
      @adamhenriksson6007 ปีที่แล้ว

      @@MichiganTypeScript Prepare...
      from enum import Enum
      class Day(Enum):
      MONDAY = 1
      TUESDAY = 2
      WEDNESDAY = 3
      # print the enum member
      print(Day.MONDAY) # Day.MONDAY
      # get the name of the enum member
      print(Day.MONDAY.name) # "MONDAY"
      # get the value of the enum member
      print(Day.MONDAY.value) # 1
      You can iterate through enums, you can compare contents like a set or list, get the length of enums, match against enum keys, and even call the enum class itself like a function to get the enum value. It's like a combination of every single data structure and a hilarious punchline to a programming joke that everyone forgot.

    • @adamhenriksson6007
      @adamhenriksson6007 ปีที่แล้ว

      Sadly, the only thing you cannot do is add or remove enum members dynamically. Don't worry though, there is a library for that.... 🤦

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      @@adamhenriksson6007 wow you weren't kidding

  • @NootNooot
    @NootNooot ปีที่แล้ว +1

    I really wonder how you can love such language.

  • @aram5642
    @aram5642 ปีที่แล้ว

    Enums are great... until you need to display a dropdown with all possible values.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      Even the, Objects will fail you because they are unordered structures. Great point!

    • @aram5642
      @aram5642 ปีที่แล้ว

      @@MichiganTypeScript but with objects, I can turn them into Object.entries and sort to my liking :)

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      @@aram5642 100%

  • @ACHTech20
    @ACHTech20 ปีที่แล้ว

    6:11 first bench 2nd guy, he is like do I need to clap.

  • @fabionunes2793
    @fabionunes2793 ปีที่แล้ว

    The part that he was complaining about tje object transpiled, well... It's because an enum is a simple map to enforce a key value. He was complaining about the nain reason of an enum. What a waste of time!

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      because TypeScript doesn't have what other languages refer to as opaque types. the example he shows where a function will accept any number for an argument typed as an enum is a great example of the kind of pitfall you don't want enums to allow.
      All the same, hopefully your day got better after watching this one. apologies for failing to meet your expectations

  • @GuiltyJit
    @GuiltyJit ปีที่แล้ว

    I'm throwing away enum as much as possible

  • @paherbst524
    @paherbst524 ปีที่แล้ว

    Ada handles enums the best

  • @LarsRyeJeppesen
    @LarsRyeJeppesen ปีที่แล้ว

    Thanks

  • @TheRavageFang
    @TheRavageFang ปีที่แล้ว +1

    12:28 that laugh 😂

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I had a really tough time not making a separate chapter for it. it's wonderful isn't it?

  • @XTANCE
    @XTANCE ปีที่แล้ว

    Wow people are chill in that Michigan or wherever you at.
    Here someone says "terrible" about others code he might get his face wrecked.

    • @Grilinctus
      @Grilinctus ปีที่แล้ว

      Wow, that’s messed up.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      it's cold and chilly here, you got that much right!

  • @loucyx
    @loucyx ปีที่แล้ว +23

    I agree enums are terrible, but your points seem uninformed:
    1. The values sorting issue isn't an issue if you use enums correctly. Namely, it would be best if you didn't use that 1 directly, but instead do comparisons and mapping with the enum itself:
    // Thing you shouldn't do
    if (value === 1)
    // This is how it should look like
    if (value === AuthMethod.voice)
    2. The object in runtime has that shape because:
    // This gives you 1
    AuthMethod.voice
    // This gives you a "voice."
    AuthMethod[AuthMethod.voice]
    And you can configure TS to emit the enum values instead of that object.
    3. Enums as arguments take any number to enable bitflags. As you showed, the solution is to use strings.
    4. The problem with the union type is if the string changes in the future, you have to go to every place used and fix it, while with the enum, you can do F2 and rename the value.
    Cheers!

    • @Krmpfpks
      @Krmpfpks ปีที่แล้ว +7

      1) is an issue if you store values in json or a database.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      great explanation!

    • @trapfethen
      @trapfethen ปีที่แล้ว +2

      1) is an issue when you serialize and deserialize data. If you never save the enum values to persistent storage then you avoid this pitfall. The moment you go to save this value somewhere, you will no have to either contend with this potential, or run face first into it at some later point.

    • @loucyx
      @loucyx ปีที่แล้ว +1

      @@trapfethen there are ways of dealing with that shortcoming (TS is not the first language to have enums that work that way). Basically you have models that are kept aligned with your types, so when you change your enums, either the DB is updated with the new values, or a map is created for old values. Either way I'm doing way too much work to "defend" enums when I 100% agree they suck and there are better alternatives like just using a plain object.

    • @trapfethen
      @trapfethen ปีที่แล้ว +1

      @@loucyx Yeah, those are the work-arounds we typically see; however, new devs (or even just devs that aren't familiar with enums) can often run into this problem without realizing.
      Like you said, you've already put in more time defending enums because you agree they have significant shortcomings. I won't press you to defend a stance you don't actively take. I appreciate the dialog, and hope you have an excellent day!

  • @ColinRichardson
    @ColinRichardson ปีที่แล้ว +38

    What these guys may have benefitted from was putting the 4 types of enums into typescript online playground so you can see the outputted JS "live".
    So they can actually see the object that using an enum actually produces. This MAY have helped the guy in the back understand.
    (The 4 types being, enum with no implicit values, enum with explicit numbers, enum with strings, and the dreaded enum with mixed values+duplicated)

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      that's a fantastic point. TypeScript is changing the way they do enums in 5.0 github.com/microsoft/TypeScript/pull/50528 and when a talk on that happens I'll be sure to ask the speaker to show this. it would really make it easer to see. really great suggestion.

    • @ColinRichardson
      @ColinRichardson ปีที่แล้ว

      @@MichiganTypeScript Thanks for the heads up with the upcoming TS 5.0 I love knowing about future features But unless they jump into my lap, I can never be bothered to research them as a lot of the time they drop the proposals and I get all excited for nothing. Fingers crossed for this enum feature.
      Just to let you know the URL has the ) added to it above. Simple fix but others may not spot it in the future.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      @@ColinRichardson thanks! updated the URL!

  • @SadieandCompany
    @SadieandCompany ปีที่แล้ว +3

    If you teaching people (and its serious), stop saying the reason is because "enums are terrible". Im 3 min in and that was used at least 4 times...

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I think it was meant more lightheartedly, but on a more serious note: do you disagree that they're terrible?

  • @gleysonsantos3960
    @gleysonsantos3960 ปีที่แล้ว +37

    I wouldnt hate this kind of school

  • @beeman-dev
    @beeman-dev ปีที่แล้ว +2

    Sorry but I think it's a real far fetched problem. Use Enums with a String/String pair and move on with your life. 🤷‍♂

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      totally: it's definitely not a problem that everyone has to contend with. for better or for worse, though, some codebases use the number style a lot (one of which is the typescript codebase itself)

  • @tommyinb
    @tommyinb ปีที่แล้ว +31

    Because numeric enum accepts runtime initialized values. You should not skip reading the handbook.

    • @AkaiKnight
      @AkaiKnight ปีที่แล้ว

      RTFM

    • @bzboii
      @bzboii ปีที่แล้ว +3

      But by default enums are numeric which seems like a mistake imo

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      oh snap

  • @mveronie
    @mveronie ปีที่แล้ว +13

    So having to use a string enum is just too much ... but manually declaring a new type on an object with `typeof Object[keyof typeof Object]` (and `as const`) is a better option?
    I'm not really sold on this. I'm also not a fan of enums, but I would prefer a string union in most cases.

    • @tankstechtutorials5721
      @tankstechtutorials5721 ปีที่แล้ว +1

      seemed like a bit much to me as well

    • @TheBswan
      @TheBswan ปีที่แล้ว

      Create a generic valuesof type, ez fix.

    • @ibgib
      @ibgib ปีที่แล้ว +1

      I just responded to @Piotr Kołodziejski who didn't see the light of the speaker's brilliance, so I just refer you to that comment and sum up that enums as numbers suck for logging (though are great if you're doing bitmask operations) and enums as strings preclude you from passing in the string literal. The speaker's method allows you the flexibility to use either the enum `AuthMethod.voice` or the string "voice". Personally I use just the string unions but then add on the constant when I would like the enum-like syntax for readability.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      @idgibDOTspace thanks again for the great comment!

  • @RunForPeace-hk1cu
    @RunForPeace-hk1cu ปีที่แล้ว +14

    I thought the whole point of enums is to "enumerate" values to numbers.
    If you use enums like a hashtable (map) ... use a map/object.
    Enums aren't meant to be super flexible. It was originally designed to be more efficient / less memory intensive them map/object because it is done at compile time.
    Since Javascript is a interpretive language, enums is kinda pointless unless you are running performance sensitive code, which javascript almost never do.
    I don't understand what the presenter was doing really.

    • @lurnt5763
      @lurnt5763 ปีที่แล้ว +1

      The presenter states what enums SHOULD be doing (which is how languages like Java support enums): only allowing a set of PREDEFINED constraints. The only reason they enumerate to numbers is for the space efficiency as you mentioned, but that is NOT the point of an enum. We want these types to only take up one of a finite number of possible, discrete values.
      In typescript, an enum type is not an actually distinct type -- it is just a regular key/value mapping as the presenter states. As a result the typescript compiler does not actually constrain your types without using string values. Look at his explanation from 2:50 onwards.
      The complaint is that in languages like java, you DO get this constraint -- enum function arguments only allow the predefined enum values, since Enum is its own Object type.

    • @lurnt5763
      @lurnt5763 ปีที่แล้ว +2

      Ok I watched the rest of the video and now I'm more on your side -- wtf is the presenter talking about? I am absolutely baffled that he suggested using objects as a better alternative. It is WAY more terse and harder to maintain especially since the object is mutable.
      The better (though not perfect) solution would have been Union types...While I also hate typescript enums this is definitely not the better solution

    • @RunForPeace-hk1cu
      @RunForPeace-hk1cu ปีที่แล้ว

      @@lurnt5763 enumerated was invented in C. They are way more efficient than storing keys and values. ESP back when memory is very much limited.
      Done at. Compile time, there’s no lookup.
      I’ve been coding since the 80s … :-)
      Enums are kinda pointless now with interpretive languages, scripts, etc … how many programs nowadays are that performance sensitive? Most developers are writing JavaScripts front end stuff … not kernel drivers :-)

    • @lurnt5763
      @lurnt5763 ปีที่แล้ว +1

      @@RunForPeace-hk1cu Lol fair I am only two years into the industry and just going from my experience using mostly Java + Typescript at work. I feel that today memory is hardly a concern as you mentioned, at least for high level application dev.
      In practice I have always used enum for the purposes of having predefined values along with strict type safety for those values. While yes there is memory optimization by enumerating it I have never considered it as a *huge* win. Either way you're probably right about the actual purpose of an enum and perhaps people have overloaded its utility over time.

  • @atxorsatti
    @atxorsatti ปีที่แล้ว +2

    I disagree to most of the things you said since TS is meant to be more readble js and more debuggable js, so it's ok to have enums behave like this. Execpt the object.values problem. This is shitty af.

  • @nomadshiba
    @nomadshiba ปีที่แล้ว +4

    i think the reason i prefer enums is, i use `const enum`, so it compiles places where the enum has been used to numbers directly
    also use "preserveConstEnums": true, so i can still have the object for the enum si still can iterate through them and etc
    BUT IF i was using your method i would use Symbols instead of strings
    better for the equality check, but it has its own downsides as well
    const A = Symbol('A')
    const B = Symbol('B')
    const Test = { A, B } as const
    type Test = typeof Test[keyof typeof Test]
    export { Test }

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      great suggestion! const enums are often forgotten about

  • @seanroach1915
    @seanroach1915 ปีที่แล้ว +4

    This talk immediately seems like it's from the perspective of someone who didn't read the handbook or reference. In reality, anyone familiar with the language would expect this behavior, and that assumption is reductive of any programming language.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      sure, but you gotta admit it's a little hard when the manual changes (sometimes dramatically) ever 4-5 months (note: TypeScript doesn't follow semver). I read "the manual" on VB6 and it hasn't changed since September 1998.

  • @nayaleezy
    @nayaleezy ปีที่แล้ว +3

    Enums are great, you're just terrible at adapting to their design.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      haha, this is a great one. I'm gonna save this somewhere.

  • @LesterFernandezIO
    @LesterFernandezIO ปีที่แล้ว +3

    I think we gotta be careful with how we use enums and this talk is good for bringing awareness to the edge cases. But I do think it still has good use cases. One is code-readability. When you see an enum in code, it’s intent and purpose is very clear. But if you use an object, you would maybe need to leave an additional comment in the code; it’s not as clear. Also, when you only care about something’s state and want to track it with arbitrary values, enums with string values are great.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I appreciate the spirit of what you're getting at. I wish the implementation for enums was different and without some of these pitfalls. in the end, at least string unions can do the job pretty well these days

  • @ElCerdoBlanco
    @ElCerdoBlanco หลายเดือนก่อน

    Actually I do like a good rant about JavaScript/TypeScript being terrible languages, but most of the problems here are just caused by not understanding, what enums are and how they work. Most of the problems addressed here would also pop up in most other languages.

  • @xTheZapper
    @xTheZapper ปีที่แล้ว +17

    The first point about adding a new entry and having the enum recalculate the associated numbers is a strength not a downside. It means you don't have to make stupid rules about only adding on the end, or manually numbering yourself. If this is an issue because you're in the situation where you're comparing the actual numerical enum value then you're using enums wrong.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      sure, but what happens when your backend talks to an out-of-date frontend with completely different mappings? I've seen this happen in production and it ain't pretty

    • @trapfethen
      @trapfethen ปีที่แล้ว +3

      Serialization and Deserialization have entered the chat.

    • @xTheZapper
      @xTheZapper ปีที่แล้ว

      @@MichiganTypeScript I'd create an adapter class to sit in between the two and do all the dirty translation stuff. That way when you update the old code you just remove the adapter and avoid pollution of your nice new code.

    • @xTheZapper
      @xTheZapper ปีที่แล้ว +1

      @@trapfethen Deserialization is only an issue if you're not loading back into the original enum. MY_ENUM_VALUE might serialize into a value of 42, but it will deserialize back into the enum just fine. If the values are going to a different application with no access to the original enum then that's poor design and you need to think about producing a spec for the enum for the receiver to implement or serializing into something like json where the value can have a description.

    • @trapfethen
      @trapfethen ปีที่แล้ว

      @@xTheZapper you have fundamentally misunderstood.
      The foot gun operates in the following way. You have an enum with implicit values {cat, dog}. You have an instance of this enum with the dog value (numerically 1). You persist this value to your storage to later recall (you have now saved the numerical value of 1). You now have to extend said enum to {alligator, cat, dog}. Next time your application reloads the previously saved profile, the enum will be deserialized as cat rather than dog as cat now has the implicit value of 1. There are methods of handling this scenario, but the necessity of being aware of the pitfall and proactively implementing a method to circumvent it is what makes it a foot gun.

  • @jeramymorrill2729
    @jeramymorrill2729 ปีที่แล้ว +2

    This feels like willful ignorance of how we actually use / check against enums. yourEnum.VALUE always matches yourEnum.VALUE no matter where you pass it, and thats the point. I will say they can be annoying in reducers if used as an action.type, unfortunately TS complains way less with plain strings...

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      you know, that's a good point. enums would have been perfect for redux actions.. but sadly redux's implementation long predates being able to use TypeScript in React

  • @teC5
    @teC5 ปีที่แล้ว +62

    i disagree - enums are great and this is not much different to how they work in C for example. The fact that they get compiled to numbers make it easy to use enums as masks and easy for serialization. It sounds like the only thing you want is a range check on methods accepting the enum, other than that your example defeats many of the purposes of an enum and is gross to setup.

    • @Dorumin
      @Dorumin ปีที่แล้ว +5

      Enums are misused for bit masks :) they're invalid values, integers should be used for that. And you can simply define them as constants

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I think enums are great as a computer science construct, but it's the "how they're implemented in TypeScript" part where things start to get sticky

    • @teC5
      @teC5 ปีที่แล้ว

      @@MichiganTypeScript ah yes, that sounds reasonable. Other then the verbosity of the proposed solution I thought the end result in usage was pretty nice, great talk!

  • @mintcar
    @mintcar ปีที่แล้ว +2

    Making a union out of an array is useful sometimes, but I don't understand why he does that at the end to create the record type. A `Record` will ensure exaustiveness no matter if AuthMethod is a union or an enum, and the value wont somehow be turned into a string. I think they are confusing eachother in this clip.

  • @artuchka-profi
    @artuchka-profi 9 หลายเดือนก่อน +1

    just use string enums and don't forget to add Eslint plugin for allowing strings only

    • @MichiganTypeScript
      @MichiganTypeScript  9 หลายเดือนก่อน +1

      why not just use string unions at that point? readability or refactorability or something?

    • @artuchka-profi
      @artuchka-profi 9 หลายเดือนก่อน

      @@MichiganTypeScript
      You mean like type RPS = 'rock' | 'paper' | 'scissors' ; and then you change `paper` to `lizard` for some reason. doesn't seem like IDE would easily replace all occurances of `paper` with `lizard`. => refactoring reason.
      And how do I iterate over string unions? much easier is to do Object.values(MyEnum) => usability reason
      How do i distinguish two different type unions when they have commonly named children? for ex: `emergency` as a filter in list of calls AND `emergency` as an option for new call. => readability reason
      idk, maybe it's just my limited experience. haven't watched enough of projects :D

    • @MichiganTypeScript
      @MichiganTypeScript  9 หลายเดือนก่อน +1

      @@artuchka-profi it turns out, though, that the IDE really can replace all occurrences. give it a try! (F2+rename)
      if you're iterating over these things as values, why not use an array where the order is stable?

  • @jez9999
    @jez9999 ปีที่แล้ว

    This could just be replaced with "TypeScript is terrible". It's a band-aid on an overly-flexible underlying language and shouldn't be used for anything remotely complex or mission-critical. Use C#.

  • @themikeholm
    @themikeholm ปีที่แล้ว

    enums are terrible because enums are terrible.... maybe let's explain it with different words? granted the number values are problematic, but i don't really see the problem with string values as you put it. all I see from this video is that you want me to type a whole lot more stuff for something which might be slightly better than the builtin four character construct? i think I'll stick with enums for now than all this typeof keyof typeof malarkey

  • @salka_
    @salka_ ปีที่แล้ว

    I'd much rather have a lint rule requiring only string enums instead of having to do `as const` and the typeof stuff. And you can make a function accept string literal versions of enum values by having the param typed as `${AuthMethod}`

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      there's an ESLint rule for that isn't there? prefer-literal-enum-members or something?

  • @da-ker
    @da-ker ปีที่แล้ว

    This is a good example of someone who seems to only do JS/TS development and has no real experience with programming, structures and history of it. Because otherwise he would truly have a different look at enums in TS and in general. Enums aren't bad, the usage is in this example is.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      the typescript team themselves don't seem to agree with you. check out the release notes for 5.0: it contains some attempts to improve some of the things mentioned in this talk

  • @cnordbakk
    @cnordbakk ปีที่แล้ว

    What a weird talk and a TERRIBLE title 🤨If you can't use types right, maybe just stick to all literals.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      what would have been a better title? ....asking for a friend..

  • @ChillAutos
    @ChillAutos ปีที่แล้ว

    I can't believe all the fuss over enums. I was expecting this to go way deeper. Why is this more confusing syntax better than string enums and setting up an eslint rule once?

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      You raise a very good point about eslint being able to really help massage things

  • @sidsarasvati
    @sidsarasvati ปีที่แล้ว

    Is it some new age junior dev ranting ahead of his experience?
    Some senior engineer needs to take this guy to a) present arguments better b) have better code sense

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      nope, lots and lots of senior devs feel this way too. of course, opinions do vary

  • @-__-1025
    @-__-1025 ปีที่แล้ว

    @13:21 you could
    ...
    const AuthMethodTitiles: {[k in AuthMethod]: k} = {
    ...
    }

  • @kbsanders
    @kbsanders ปีที่แล้ว

    Frustrating when camera person/editor person cuts away from the IDE.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      thanks for this feedback, truly. we'll try to do better in this realm in the future. after all, the code is the most important part of the presentation!

  • @offroaders123
    @offroaders123 ปีที่แล้ว +5

    Great video, thank you! Yeah, enums aren't the best haha.
    I really like using the `[key: string]: CustomType` for interfaces. You can limit what kinds of types a child interface can define specifically, so you can force it to only allow specific value types for the object's keys (I think that is what the last question was about?). I'm a Minecraft guy, and I have been writing an NBT library that does this, if it is any consolation that may help explain it:
    interface CompoundTag {
    [name: string]: Tag;
    }
    (Tag is a union type of all NBT tags combined)

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      That's cool, I feel like I don't see that syntax for interfaces very often (more for TypeScript types). Is your library public? I'd love to check it out!
      p.s. how sad were you that archaeology isn't making it into 1.20?? 。゚( ゚இ‸இ゚)゚。

    • @dara-bk5rh
      @dara-bk5rh ปีที่แล้ว +1

      Isn’t that the same as Record ?

    • @offroaders123
      @offroaders123 ปีที่แล้ว +1

      @@dara-bk5rh Turns out, yeah! I actually only just read about Record yesterday, and it's a wrapper for assigning an index signature to the type.

    • @harleyspeedthrust4013
      @harleyspeedthrust4013 ปีที่แล้ว +1

      @@dara-bk5rh sure thing, but it's better because generics are butt ugly and using Record means that people now have to go look at the type definition for Record and substitute CustomType in for the type argument. also I remember creating NBT objects in Minecraft mods (for Forge) was a pain in the ass because you had to do it in Java which means you needed to go digging through a gazillion NBT-whatever interface implementations to find the right class to use, then you had to construct an object and add the nested tags which also had to be found and constructed in the same way. I think there were static methods to create these blasted NBT objects but if i remember correctly they still had their obfuscated names at the time so you weren't actually 100% sure what they did until you used them. and then if you managed to figure some of the obfuscated shit out, you couldn't submit a readable name to the MCP because their bot was constantly "locked" or something even if you had an account. every time i think about java i get a headache, that language is the absolute worst even worse than javascript

    • @offroaders123
      @offroaders123 ปีที่แล้ว

      Thought I replied to your message already, but looks like it got removed maybe? Sorry about that! My library is called NBTify, and it's on NPM and GitHub under my same username. I'd add a link to it, but that may have been why the old comment was taken down? Yeah, I hope Archeology comes part of the next update too!

  • @blargo
    @blargo ปีที่แล้ว

    2:35 "I have no idea why; there's probably a reason [enums are implemented this way]". It's so you have a way at runtime to look up the named enum value from the numeric value, and vice versa. Presenter should have taken the time to investigate this, also covered 'const enum', before declaring enums to be TERRIBLE.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      would you be at all swayed by the fact that the runtime artifact is so non-obvious to so many people is itself enough to rank it lowly?

    • @blargo
      @blargo ปีที่แล้ว

      @@MichiganTypeScript Not really. If you treat enum as a type, instead of an object, who cares how it's implemented? If the runtime implementation of enum bothers you, and you don't see the benefit of two-way mapping, just use `const enum`.
      Sure, the example of not being able to use `Object.values` is a bit surprising at first glance. However, in any real scenario, where you want a human-readable list of the enum values (or more likely, localized versions of the same), you're going to need to perform additional processing/mapping anyway, so it's kind of a non-issue.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      @@blargo I hear yah. As a library author, I care quite a bit whether the code I'm shipping to my users will be confusing to them or cause them problems (whether justified or not by the "facts of the situation" as to whether they are justified in being confused). There's definitely a very valid "RTFM" rebuttal to many of the criticisms of TypeScript's implementation of Enums.

  • @margosdesarian
    @margosdesarian ปีที่แล้ว

    You would seriously employ someone who would not put the new enum value at the end?

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      sometimes it can be something as simple as a bad merge conflict resolution that can send things off the rails re: enum number ordering

  • @maxpoulin64
    @maxpoulin64 ปีที่แล้ว +16

    One of the reasons for the numbers is you can do things like if(2 in AuthMethod) to validate if an input value is a valid value for the enum.
    The number thing is not useful for external APIs, but it's useful for data structures that remain local because you can do integer operations. For example, state machines.
    It's not Rust enums but it's pretty decent for JavaScript and what you'd use enums for in JavaScript. Gotta keep in mind that all the TypeScript is gone once compiled, so it can't prevent you from having bad values at runtime, only basic checks at compile time.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      Finally. Finally someone mentioned Rust enums. I really really love Rust enums. At first they blew my mind, then I thought I understood them, then they blew my mind again.. today, all I can say for sure is that they're clearly great.

    • @harleyspeedthrust4013
      @harleyspeedthrust4013 ปีที่แล้ว

      @@MichiganTypeScript rust enums are fantastic. i've always been underwhelmed by enums until rust enums came along

    • @dealloc
      @dealloc ปีที่แล้ว

      @@MichiganTypeScript Rust enums are similar to algebraic data types found in other functional languages, which makes it so powerful compared to TypeScript. But one missing feature is the ability to use a enum variants as types, like you can with TypeScript. For example `AuthMethod.sms` is a type in and of itself in TS, so you can constrain some value further. This is not possible in Rust, and not easy for them to implement either in the language, unfortunately.

    • @amh1010
      @amh1010 ปีที่แล้ว

      @maxpoulin64 if the `2 in AuthMethod` check was the reason then why doesn't that work for string enums? Like if I have `enum Foo { a = 1 }` then `1 in Foo` is true, but if I have `enum Foo { a = "A" }` then `"A" in Foo` is false. In other words, for numeric enums the runtime object's keys are the enum's keys and values, but for string enums the runtime object's keys are only the enum's keys

    • @maxpoulin64
      @maxpoulin64 ปีที่แล้ว

      @@amh1010 it's definitely not intuitive and that's where knowing what the code compiles into is useful to know, unfortunately.
      I think ultimately what it compiles down to is optimized for performance. Integers and arrays are more efficient than maps, so wherever it can it'll use that. As soon as you manually assign the values of your enums, you end up with a map instead.
      Ultimately you're probably supposed to use enums as constants and not try to do reverse lookups like that. If you really want a map or an array you should use an array, the enum is just a construct that lets the compiler do things for you. Very double edged sword for sure but it's JS...

  • @Wielorybkek
    @Wielorybkek ปีที่แล้ว +1

    I don't really see any difference between those approaches. Either way you have to agree with other people to either use objects or string unions or string valued enums etc. People will use enums anyway so... :p

    • @ibgib
      @ibgib ปีที่แล้ว

      Before enums officially came out in TS, I was using the speaker's method - but manually duplicating the `const AuthMethod` using entries like `voice: "voice" as AuthMethod`...basically the ooold way. And when enums came out, I thought the same thing as you (I was pretty excited even that I would be able to simplify the code!). But there are several huge practical differences:
      1) If you use the numbers approach, then you lose readability when logging. This is fine if you're looking for blazingly fast code in a tight loop, but really at that point, you might ask why are you using JS/TS?
      2) The strings approach that the speaker turns to around 3:45 have a HUGE problem (IMO) in that you lose the ability to choose either `AuthMethod.voice` or "voice". If you pass in just the value string literal, the compiler will complain at you saying "Argument of type '"a"' is not assignable to parameter of type 'AuthMethod'.(2345)" This for me is a non-starter, because sometimes I want to use the enum and sometimes I want to pass in the string directly with compile-time type safety.
      I'm interested in what he's doing at the veery end of the video using the new `satisfies` keyword, but I'll probably be too lazy and continue to do it the old fashioned way. (I don't even use the `keyof` shorthand he uses at 5:20 - partly because it looks cryptic but mostly because I am just old!)

    • @yikan1107
      @yikan1107 ปีที่แล้ว

      Nobody uses enums. In practice it is easier to create a file and just export const. If you need to group tuple like or cardinal information , the object is more flexible and combinable with redux functions.

    • @marcosrolando7987
      @marcosrolando7987 ปีที่แล้ว

      @@ibgib Why would you want to pass the string literal? That just seems like a really bad practice because any refactoring to the enum would require manually changing every use of the string literal instead of just modifying the enum value itself, and even ignoring that why would you "sometimes" need to use it as a string? Enums are abstractions and you should use them as such, refering the actual value in the rest of the codebase is (usually) a bad idea, and only really makes sense when translating external input to the enum.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I think there's a lint rule to completely disallow enums

  • @Gruby7C1h
    @Gruby7C1h 9 หลายเดือนก่อน

    "Am I a joke to you?" - Bit Masking.

    • @MichiganTypeScript
      @MichiganTypeScript  9 หลายเดือนก่อน

      right?? haha. the bit masking element of all of this really is a part that people miscalculate the historical relevance of.

  • @adambickford8720
    @adambickford8720 ปีที่แล้ว +4

    Type unions seem to make the most sense to me: dead simple, typesafe, exhaustive (add a value, switch will break) and discoverable (ide will offer autocomplete values just like a formal enum):
    type Bar = "one" | true | 3
    function foo(bar : Bar) : string {
    switch (bar) {
    case "one": return "won"
    case true : return "blue"
    case 3 : return "bout tree fiddy"
    }
    }
    function baz() {
    assert("won" == foo("one"))
    assert("blue" == foo(true))
    assert("bout tree fiddy" == foo(3))
    }
    baz()
    Honestly, i wouldn't even create a 'Bar' type if `foo()` is the only call site, just inline it:
    function foo(bar : "one" | true | 3) : string {...}

    • @TheNewTimeNetwork
      @TheNewTimeNetwork ปีที่แล้ว

      But how do you iterate over all possible values? Imagine like `Bar.values.map(...);` I think that's not possible, because you have *only* a type, and a type can not be used as a value.
      What you can do is:
      const Bar = ["one", true, 3] as const;
      type Bar = typeof Bar[number];
      The second line evaluates to `type Bar = "one" | true | 3`, but you can also use `Bar.map()`, `Bar.forEach()` etc. - Bar is a type and also a const array.
      From this approach on, if you exchange the const array for a const object, you arrive at the approach presented in the video, which provides you with named constants, `Object.keys(Bar)` and `Object.values(Bar)`:
      const Bar = { A: "one", B: true, C: 3 } as const;
      type Bar = typeof Bar[keyof typeof Bar]; //

    • @adambickford8720
      @adambickford8720 ปีที่แล้ว +1

      ​@@TheNewTimeNetwork That's way overthinking it imo. i've never had those exotic needs and the straight simplicity easily outweighs that trivia/edge case.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      @TheNewTimeNetwork for whatever it's worth, you can iterate through types with "distributive conditional types" and "mapped types" (both different approaches, but often interchangeable)

  • @Kubatko
    @Kubatko ปีที่แล้ว

    Not sure, from the video I see that enums are perfectly safe to use and work exactly as I would expect. As long as you understand them which should be the case for any part of language you use.
    Any of the alternatives I saw after the initial intro seem to be worse cases and are exactly the reasons why I would use enums.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      that's fair. if it works for you and it makes sense to you then go for it. I've noticed it becomes more of a problem when working with teams (but of course that depends on the makeup of the team)

  • @jaypacsky
    @jaypacsky ปีที่แล้ว

    Enum, interfaces in the TS world are useless

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      the enums part I agree with, but why do you find interfaces to be useless? without interfaces module augmentation gets a lot harder.

  • @danteDeveloper
    @danteDeveloper ปีที่แล้ว

    super nice tips about enums!

  • @TheCsakbalint
    @TheCsakbalint ปีที่แล้ว +8

    There is a reason, why we require even from junior developers to know why the JavaScript (and TypeScript) is based on duck-typing.
    If you know that, you know, why the method accepts any number if the values of your enum are numbers. This is the reason why you should always use string values for enum values, because a set of strings is also a valid type and in that way you can limit the amount of possible values you accept.

    • @TheCsakbalint
      @TheCsakbalint ปีที่แล้ว

      Not knowing something and saying it's bad does seem shallow thinking to me.

    • @Monstermash355
      @Monstermash355 ปีที่แล้ว

      Most developers don't know that and use numbers, so yes it's bad in the real world, you might aswell just forbid using it

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      yep, however even the TypeScript team is always looking for ways to close this gap. for example strict function types: www.typescriptlang.org/tsconfig#strictFunctionTypes

    • @harleyspeedthrust4013
      @harleyspeedthrust4013 ปีที่แล้ว

      @@MichiganTypeScript why would this even be an option? the point of typescript is to add strong typing so why would it ever be allowed to assign a `(string) => whatever` to something that should be a `(string | number) => whatever`?

    • @TheCsakbalint
      @TheCsakbalint ปีที่แล้ว

      @@harleyspeedthrust4013 For example introducing TypeScript to a JavaScript project gradually.

  • @dealloc
    @dealloc ปีที่แล้ว

    Enums have two problems; one is that non-const enums generates more runtime code than is necessary-it's not emitting an object.
    The semantics are also different between usage in TS and non-TS code bases; since const enum with string values does not allow TS users passing raw strings, but requires non-TS users to as they cannot use the enum type; but will produce incorrect documentation.
    Unions solves all of this, because they are interoperable and consistent and provides the same type safety as enums. If you want to use numbers as values and provide more context, just export traditional constants. If you want to constrain them, you can always export a union of those types.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      fantastic comment! I know a lot of people that do exactly what you're suggesting: use string unions

  • @rons96
    @rons96 ปีที่แล้ว

    Everyone speak bad things about every lang, most to be promoted somehow, but devs never join to improve some lang to be recommended to all situations together just with simple changing in settings. Thousands of langs created along time to replace older langs and the reason is most of devs want to be rich with they created new langs everyday. For example: deno was waste time, why not improve node? And Rust, why not release improved C? The many options just make fix projects hard and confusing to new devs choose the "best" to start studying

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      These are great questions you pose as examples. Deno is effectively _is_ improving node. You might think of it as node 2.0, conceptually speaking. And for Rust, I wondered the same thing before I tried it but there'd simply be no way to "incrementally improve C until you end up at Rust". It's just a different thing with a different set of goals (although, of course, those two sets can sometimes overlap).
      Still, your overall point is a great one.

  • @AvenDonn
    @AvenDonn ปีที่แล้ว

    Forcing updates when you add one more thing is potentially bad.
    Lots of code is "If a, then do x. If b, then do y. Otherwise just do z"

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      totally, that's where I think people get into trouble

  • @charlesoconor
    @charlesoconor ปีที่แล้ว

    Is no one going to mention why the enum with int values has both! It’s so you can check if a value is part of the enum. You want the ability to check if the int is there as well as the key and since they are guaranteed to never have overlap you. Double backed enums. Sadly you can’t guarantee that in a string enum that some crazy person would map key foo to value bar and then a key bar to foo. So you lose the ability to go from keys to values. Would be cool if it was a compile option. It’s why I prefer int enums

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      on this part:
      > You want the ability to check if the int is there as well as the key and since they are guaranteed to never have overlap you.
      I've heard lots of people say this and while I certainly believe you... can you give a real example? I have never wanted this (as far as I understand it) and I've never seen a situation where someone else has wanted it either... and you're not the 20th person I've asked..
      I realize "make me an example to educate me" might not be something you have time for, but just thought I'd throw it out there in case you know of a good open-source example where double backed enums are critical.

  • @thepetesmith
    @thepetesmith ปีที่แล้ว

    Try the Record utility type.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I used to dislike the Record helper type but now I think it's really helpful for some situations.

  • @ivanjermakov
    @ivanjermakov ปีที่แล้ว

    I totally agree that enums in TypeScript are a total mess. For personal projects, I always use literal types, e.g. type AuthMethod = 'push' | 'voice' | 'sms'

  • @SongZoneChanel
    @SongZoneChanel ปีที่แล้ว

    thank 4 share

  • @Nemhesis10
    @Nemhesis10 ปีที่แล้ว

    It's beautiful...

  • @gillall4828
    @gillall4828 ปีที่แล้ว +2

    Why not? type AuthMethod = "Push" | "SMS" | "Voice"

    • @LarsRyeJeppesen
      @LarsRyeJeppesen ปีที่แล้ว +1

      Much harder to change values later, no iterator

    • @Loserfr
      @Loserfr ปีที่แล้ว

      Typing doesn't give you the same thing as an enum. As you can see in the video, you get values from the enum whereas you don't get values from a type.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      A lot of people go for that, yep. I think the part people don't love is where it makes it a little tricky to search your codebase for each and every usage, whereas LSP tools will show you implementations if you use an enum.

  • @paherbst524
    @paherbst524 ปีที่แล้ว

    Just enums? How about "TS is terrible" ;)

  • @gaddp
    @gaddp ปีที่แล้ว

    Typescript Enums are TERRIBLE, but vim is the BEST.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      have you heard of emacs? my understanding is that it has vim bindings but I haven't tried it yet because I'm still upgrading my machine from 32bit XP

  • @2Fast4Mellow
    @2Fast4Mellow ปีที่แล้ว

    If you work with large codebases, stop using enums where interfaces makes more sense. Enum = enumeration. Javascript is not object oriented, but it does emulate it. But what it creates a associative array where members can be a function or a value. In order to support both the enum name and it's value, TS needs to create an array that contains both. That is why object.values gives you both.
    However if you use an interface, you have to pass an actually instance that conforms to the interface to 'DoSomething' In order to know where you need to alter the code if you introduce a new auth method, you can simply find all places where the interface is used as an argument. Using reflection you can find all implementations of that interface and put it in an assoc array which can be used to show the auth methods names. In pretty much every language enums are evil! Enums are just a construct to remove magic numbers and makes reading the code easier... Am programming for 35+ years and enums still create the same mess as in the 80s...

    • @dealloc
      @dealloc ปีที่แล้ว

      Interfaces and enums are completely different concepts. Use unions. Enums generates more code than necessary, and const enums does not allow passing raw string values, which means that JS code and TS code have different semantics and so are not interoperable.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      The only language I've seen an enum implementation and that I loved was rust

  • @nsk8ter524
    @nsk8ter524 ปีที่แล้ว

    Enums suck because a type of string unions does its job better. `type Whatever = 'foo' | 'bar' | 'baz'`. Then you don't have to port the enum all over the app.

    • @LarsRyeJeppesen
      @LarsRyeJeppesen ปีที่แล้ว

      Lots of issues with that.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      totally. unfortunately unions weren't in the language until 1.4, so we're probably stuck with enums for the foreseeable future

  • @xBiggs
    @xBiggs ปีที่แล้ว

    A lot of these problems are not specific to typescript. Enums often don't give the functionality of a closed set of numbers like people truly want.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      can you give some other examples of languages you have in mind? I don't follow exactly and I'm curious

    • @xBiggs
      @xBiggs ปีที่แล้ว

      @@MichiganTypeScript C and C++ enums decay down to Integer types. If I have a function that accepts an enum parameter, you can supply an argument literal that isn't in the enums range. The same applies if you have an enum variable, you can assign a value outside the enums specified range. Enums arent a closed set of numbers in most languages

  • @FelixFaerber
    @FelixFaerber ปีที่แล้ว

    channel 5 sticker :)

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      sorry, I don't have cable. what's on channel 5?

    • @FelixFaerber
      @FelixFaerber ปีที่แล้ว

      @@MichiganTypeScript www.youtube.com/@Channel5TH-cam

  • @Verrisin
    @Verrisin ปีที่แล้ว

    I always thought TS just uses a Union of strings.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      It's definitely highly standard to just use a string union, but sadly some codebases are really stuck on enums despite the problems their implementation in TypeScript causes.

  • @loucadufault6549
    @loucadufault6549 ปีที่แล้ว

    If I watch a 15 minute video about TS enums, I kinda expect not to be greeted with two "I have no idea why" within the first 3 minutes of the video, that can easily be found by a little research...
    I am very skeptical to spend my time listening to a presentation where the presenter isn't aware of basic TS concepts like duck typing, and put two and two together to realize that because the enum members resolve to numbers (at least in this setup), and typescript cannot narrow numbers, then of course the method accepts any number due to duck-typing.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      Sounds like you've got a talk of your own brewing here. Feel free to reach out!

    • @loucadufault6549
      @loucadufault6549 ปีที่แล้ว

      For what it's worth the rest of the presentation was very informative and it's clear from the questions the presenter is quite knowledgeable, I guess just an odd decision to start the presentation that way...
      Definitely learned a thing or two from the answers during the questions round.

    • @loucadufault6549
      @loucadufault6549 ปีที่แล้ว

      @@MichiganTypeScript haha I've amended my comment as I feel it was a little harsh. And I definitely don't have much to share as I still feel I have even more to learn.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      @@loucadufault6549 that's very kind of you to say! thanks for stopping by!

  • @kirsanov2008
    @kirsanov2008 ปีที่แล้ว +1

    enums are okay, TERRIBLE is that you don't learn your tools and rush to the stage to show people that enums are TERRIBLE 😲, it's bs

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      genuinely, I'd love to know what you're referencing that wasn't learned about the tools

  • @benjamin_fdw
    @benjamin_fdw ปีที่แล้ว

    This was very interesting, I had to do this infamous trick with the typeof thing especially with templates because I was on a sort of data oriented architecture (you know how crazy one can go on a side project) and it is not easy to figure out but it works pretty well.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      I'd love to see more on this: do you have an example?

    • @benjamin_fdw
      @benjamin_fdw ปีที่แล้ว

      @@MichiganTypeScript I think I was talking about something like this:
      ```
      export const AbilityNames = [
      'strength',
      'dexterity',
      'constitution',
      'intelligence',
      'wisdom',
      'charisma',
      ] as const;
      type AbilityTuple = typeof AbilityNames;
      // this will contain the Abilities as a string union
      export type Ability = AbilityTuple[number];
      // this type can be templated
      export type Abilities = {
      [key in Ability]: number;
      };
      /**
      * Abilities is equivalent to Record
      */
      ```

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      @@benjamin_fdw very interesting! thanks for explaining!

  • @jamie9419
    @jamie9419 ปีที่แล้ว +2

    I love enums. I think the best implementation of enums is in C++. I get particularly annoyed with how Python requires setting a value. I think it is best to only use integers and it should not ever matter what the value is (So it should not be used for things like user data that will change often!). Also using a string is exactly what we are trying to get away from by using enums! Enums are great for things like states, things that have semantic meaning that we want to group in an unordered list, but we only care about the symbolic! It is for the programmer so that we have a nmemonic for some kind of option or state. Before enums, you either had to declare constants for each thing, or use a list of DEFINEs that are evaluated at compile time. That's why I say it shouldn't be used for data that changes where you are going to download the integer value or whatever from a database across changes to the enum values. It should be used for non-persistent internal data where it doesn't matter if the values are consistent from one compile of the software to the next. Data objects for user data in a web-app would not fit this description imho, as they are expected to persist and be carried across updates to the API and database schema. I don't think that enums should be used for data that requires migration or translation as an object format changes. They should be used for lower level run-time states and settings so that the programmer doesn't have to care whether it is the third or seventh or whatever item on the list. In the case of the example for this video, I quite frankly don't understand why you would be making an enum for methods. Methods already act like enums when you're writing code. You can call . without giving an index to the object. That is essentially already acting like an enum, so why would you need "another one" in this case?

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว +1

      I agree with a lot of this. I don't know for sure, but wonder if we were to go back in time and never have enums in TypeScript... I would.. haha

    • @jamie9419
      @jamie9419 ปีที่แล้ว

      @@MichiganTypeScript I can appreciate that and I hope I didn't come off any kind of negative way. I still consider myself a "junior" developer, but as an associate working on compilers for a mainframe OS, I have gained a bit of perspective. I by no means consider myself authoritative. But you should see some of the DEFINEs we have in ALGOL, etc. oh boy. ("Extended ALGOL60" has DEFINEs that can simply say SOMETHING(X) = and it is all evaluated by name. Also, the default way of handing parameters in procedure calls are "by-name" rather than by-value or by-reference, meaning that the parameters are evaluated by their symbolic rather than a memory address or literal value. The difference from call-by-reference is subtle, but it basically means if you pass an expression as a "formal parameter", that expression itself will be re-evaluated everytime the "actual parameter" is referenced) Not to mention the GOTOs.
      I think I fell in love with enums when I tried following along with a C++ RPG game engine project using SFML on youtube, and they were very useful for defining states like IDLE, or WALKING_LEFT, etc. Very nice to have those as identifiers that an IDE can recognize, rather than (worst case) using a string literal value and checking "if state == "WALK_LEFT"", which is something I perhaps unfairly associate with Python, because I happened to see it in some Python code and it bothered me (lol). The nice thing about having a list of states as an enum like that is that you can add more of them, change the order, etc. and you don't have to worry about it. As I said, my perspective on this only applies to things that don't need to be transferred as persistent data across compiles, or communicated between potentially disparate software versions where the literal value may have changed.
      Also, would like to say I'm sure there is some use case for enumerating methods, I just thought that the simple use case of enums is for a situation where you want values that act like methods of an object, but aren't methods, and you would like them to be defined in a way that is recognized and accounted for by your IDE/compiler. :)

    • @philipbotha6718
      @philipbotha6718 ปีที่แล้ว +1

      @@jamie9419 Scoped enums in C++ are one of my favourite features. The order of the enums are only important if you're serialising the enum or using the underlying value directly. But then it is better to explicitly assign the value to the enum in its definition.

  • @nayaleezy
    @nayaleezy ปีที่แล้ว +1

    Hyperbolic much?

  • @jeremiasnater4288
    @jeremiasnater4288 ปีที่แล้ว +2

    i would use string enums over number enums and i agree with some of the points. But some of tge reasoning here is really bad, and as you are doing a talk about this you should know that the keys and values are in the enum object so that it can be looked up in both ways.

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      right, that much is clear, but _why_ would you need to look them up both ways? care to share a codepen demonstrating this? asking for a friend.

  • @Stubbelur
    @Stubbelur ปีที่แล้ว

    For those confused, like me, about wth was going on at 12:00, here is ChatGPT's explanation:
    This code defines a type called AuthMethod that corresponds to the string values in the authMethods array. The as const assertion is used to ensure that the authMethods array is treated as a tuple type rather than a string array.
    Next, the code defines an object called AuthMethod that has properties with the keys of each value in the authMethods array, and string values for each property. For example, the push property has the value "Push".
    Finally, the code uses an index type k in AuthMethod to iterate over each value in the authMethods array and create an object property with the key equal to the current value, and the value equal to the corresponding string value in the AuthMethod object. For example, the push property of the object is created with a key of "push" and a value of "Push".

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      wow. this is amazing. I'm gonna have to check this out!

  • @DioArsya
    @DioArsya ปีที่แล้ว

    I want to be there.... haha

  • @tak68tak
    @tak68tak ปีที่แล้ว

    terrible camera work

  • @21mighty86
    @21mighty86 ปีที่แล้ว +6

    Good video, if you meant it as a joke

  • @robbieskonieczny9464
    @robbieskonieczny9464 ปีที่แล้ว

    I also dislike how you can't abstract enum functions compared to a language like Java.

  • @enfieldli9296
    @enfieldli9296 ปีที่แล้ว

    Interesting and refreshing, thank you!

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      Any time. Let us know if there's anything you'd like to hear about next :)

  • @issy_dev
    @issy_dev ปีที่แล้ว +1

    Really good talk, thank you for sharing these pitfalls and solutions

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      Our pleasure! let us know if there's anything you'd like to see next

  • @naadodi_tamilan
    @naadodi_tamilan ปีที่แล้ว

    First of all if you are going to `doThing` and pass multiple types of arguments into it to do multiple things, then you need to separate them out as doSMSThing, doPushThing and so on... Read Code Smell before you post something like this

    • @MichiganTypeScript
      @MichiganTypeScript  ปีที่แล้ว

      is that book on Amazon or something? got an affiliate link handy by any chance?

    • @naadodi_tamilan
      @naadodi_tamilan ปีที่แล้ว

      Not an affiliate link

  • @sougataghar1179
    @sougataghar1179 ปีที่แล้ว +4

    Typescript is terrible itself

  • @mikaputa2194
    @mikaputa2194 ปีที่แล้ว

    Great chanel, thx