Let's Talk About TypeScript's Worst Feature

แชร์
ฝัง
  • เผยแพร่เมื่อ 5 ต.ค. 2024
  • Please tell me you're not still using enums. Let's leave them behind in 2022.
    #t3stack #fullstack #webdevelopment
    ALL MY VIDEOS ARE POSTED EARLY ON PATREON / t3dotgg
    Everything else (Twitch, Twitter, Discord & my blog): t3.gg/links
    S/O Mir for the awesome edit 🙏
  • วิทยาศาสตร์และเทคโนโลยี

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

  • @t3dotgg
    @t3dotgg  ปีที่แล้ว +26

    Some of y'all are REALLY misreading the example at 0:50. Read this slightly changed version before commenting about it.
    const user = {id: 1, role: UserRole.User)
    if (!user.role) {
    user.role = UserRole.Unassigned
    }

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

      Say you were able to tolerate assigning the first variant of UserRole to =1 to avoid this issue. Would this change your opinion?

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

      I don't think this is the case. People here raised legitimate questions because you completely ignored the fact you can just do
      enum User {
      Admin = "Admin",
      Staff = "Staff",
      }
      To address enums without even mentioning that in this context is kinda funny. Then you just screamed thats just string literals with extra steps, which again is stupid. Typescript is just javascript with extra steps, does that make it worse? Ofc my example is disingenuous as well but thats the point, I didnt explain any of the other benefits of typescript, if I made a video like that i'd be right to have people calling me out for my shitty example.

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

      @@tomashaddad '
      _"Number is terrible js feature, 0 may get interpreted to *false*. Here i show you how i avoid that with an array of string containing every number... you can even iterate it"_
      (feel free to delete my comment theo.)

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

      do you always treat your viewers as morons? get off your horse

    • @powerinemesitsunday236
      @powerinemesitsunday236 ปีที่แล้ว +10

      @@ChillAutos Thank you. I was about to comment the same. I use enums a lot (exactly how you described), and I don't see how his boilerplate-y code is better than enums. Utter crap.🙄
      I could iterate through an enum, use it as a (string constant) type and use its values as well (like an object just as his boilerplate-y code showed) and the DX is way better.
      Theo, you should not talk about a feature if you're not really sure how it works. Do your research well before coming out at us. 🙄

  • @alisharobinson7146
    @alisharobinson7146 ปีที่แล้ว +185

    Use it like so
    enum ThemeOption {
    lightTheme = 'light-theme',
    darkTheme = 'dark-theme',
    }
    The reason for enums is for more readable global reused variable values when referencing them in HTML or TS. You just have to make each value equal to a string value that makes sense otherwise you will get the weird number index value. People are more likely to understand the enum than making custom types based on an array which is more advanced. I teach typescript and can confirm this is less overhead than your way and more readable.

    • @aaronv7685
      @aaronv7685 ปีที่แล้ว +22

      right I think this is easily solved by string enums?

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

      This.

    • @HOLYCC
      @HOLYCC ปีที่แล้ว +15

      This is the way. I don't know how the hating of enum started becoming a trend, but for a set of options, why does Theo's path require multiple blocks, instead of just doing an enum this way. Cleaner, more readable, and most importantly it accomplishes the same thing.

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

      Very agree with your answer 👍🏻👍🏻👍🏻

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

      This is how we use it at my day job too.

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

    Why would you ever write the condition at 0:50. It doesn't make any sense.

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

      @Duy Phạm Bá Xuân Yes, I saw that in another thread. Still no reason to do if (Enum.VARIANT) I see why you would do if (user.role). I'd do !== null or something though (and use TS to ensure it could only be those two types)

    • @DuyPham-kk8hw
      @DuyPham-kk8hw ปีที่แล้ว

      @@MarcelRobitaille Oh! I usually have to check it at work because different enum has different logic
      For example:
      If(ERoles.Admin){}
      else if(ERoles.Employee){}
      So the video makes sense to me

    • @DuyPham-kk8hw
      @DuyPham-kk8hw ปีที่แล้ว +1

      @@MarcelRobitailleDoes it make sense to you ?

    • @DuyPham-kk8hw
      @DuyPham-kk8hw ปีที่แล้ว +1

      @@MarcelRobitaille oh, i get your idea now.. yea :D Hmm, theres no reason to do if(Enum.VARIANT).

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

      @@DuyPham-kk8hw That code would be for the instance of the enum, not the enum type itself

  • @gamertike
    @gamertike ปีที่แล้ว +34

    In defence of enumes, when have you ever used if (UserRole.User) { ... } instead of if (user.role === UserRole.User) { ... }?

    • @Andreas_Mann
      @Andreas_Mann 2 หลายเดือนก่อน +1

      first time i watched one of his vids and that alone told me he's a clown

  • @sihoonkim1502
    @sihoonkim1502 ปีที่แล้ว +96

    Or you can just do this..! U dont have the "zero" issue with the first enum element, u get typesafety, And u can easily iterate on it with Object.values(UserRoles).map( role => .... )
    enum UserRoles {
    User = 'User',
    Admin = 'Admin',
    Staff = 'Staff'
    }

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

      Agree 👍
      I believe it's much simpler and ideomatic than having an array

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

      This is just string literal types with extra steps

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

      @@t3dotgg is it though? This seems to be on par with your second array example. With the added benefit that everyone knows what an enum is and it's pretty clear exactly what is happening here. I really don't think this is extra steps at all, and if there is still an issue with the example posted here then I'd be interested to hear it. I myself are started using string literals a lot recently like your first example after watching someone else's video which was very similar but it still doesn't seem super clear that enums suck completely, just that enums like in your first example do suck.

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

      This is the way

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

      Its even more useful when the key and value arent the same, so you can do colors.brown and not memorize hex values etx

  • @loomy5113
    @loomy5113 ปีที่แล้ว +44

    Perhaps I'm not understanding the issue fully, but aren't these problems already solvable by either declaring the first value of the enum as 1 (e.g. enum UserRoles { User = 1, Admin, ... }), or by declaring your enum values as string literals (e.g. enum UserRoles { User = "user", ... })?

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

      That’s what I came to type. That would have been a much easier solution.
      Golang uses constant/iota instead of Enums and you can change the default value (also 0) with them as well.

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

      th-cam.com/video/jjMbPt_H3RQ/w-d-xo.html
      I came across this explanation and it's much clearer to why enums are bad compare to theo's, do check it out

  • @iMagicGraalOnline
    @iMagicGraalOnline ปีที่แล้ว +64

    For the "if (UserRole.User)" returning a falsy, why would you EVER want to check for that? Even if you wanted to check if it exists, its an enum which will never be changed by the code you write so as a developer you'd just know it does exist. Thats like checking for an "if (false)" statement and being surprised that it's not hit.

    • @yapdog
      @yapdog ปีที่แล้ว +29

      That's exactly what I'm saying. I have no idea what the problem is that he's illustrating.

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

      the case i would assume it comes up in is when the role is part of another object like User, then checking if they have a role set like `if (user.role && user.role === UserRole.User)`, if the user.role is 0 it will be falsey and the condition will be false even if they actually are a UserRole.User
      of course in this case its probably not necessary to check the role before equality comparison, but regardless the situation is probably not specifically checking the enum declared itself but rather when its part of another type

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

      Think about getting data back from some api with that user role and you're checking to see if that data was returned correctly.

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

      @@ChillAutos You'd have exactly the same issue if the field was an integer, and 0 would even be a valid value in that case.
      I just don't check anything in JS/TS without ===, it's consistent across all situations and the "cleaner" code ain't worth it.

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

      Yeah, I've never seen that someone does something like if (UserRole.User) with enum. It's nonsense.

  • @qorzzz9252
    @qorzzz9252 ปีที่แล้ว +19

    String enums are fine IMO. What you demonstrated as the "problem" is this video is easily mitigated by adding string initializers to the enum values.
    Your solution does give access to an array of string values you can iterate (such as dropdown in your case) however, your solution also has a pretty massive flaw in that you must do checks against string literals. For example, with your solution you cannot say: if(user.role === UserRoles.Admin) instead you must write if(user.role === "Admin") and this is incredibly cumbersome if you have either: A) Many points where you check these values or B) many values that you do checks against.

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

    Nonono. Please, stop forcing people to stop use enums!
    Nobody checks if (UserRole.User). It’s nonsense! Check if (user.role === UserRole.User). That’s correct for any language

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

    Here in Brazil, we would call you a Caga Regra but with affection and love
    This video only reminds me of that guy who told Mike Tyson to grab him by his wrists and made an awesome karate move to get out, and Mike just asked, " Why would I grab you by your wrists if I can punch you in the face?
    Why would I check the truthfulness of an enum value?

  • @pxkqd
    @pxkqd ปีที่แล้ว +73

    Thanks for covering this up for everyone!
    I prefer the variant with object instead of array:
    const UserRoles = {
    User: 'user',
    Admin: 'admin',
    Staff: 'staff',
    } as const
    type UserRole = ObjectValues
    Using this auxiliary type ObjectValues = T[keyof T]
    This way you still get UserRoles.Admin which is one of the features of enums people like.

    • @paulrukavishnikov5171
      @paulrukavishnikov5171 ปีที่แล้ว +19

      Why not this then?
      enum UserRoles {
      User = 'user'
      Admin = 'admin'
      }

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

      They can have the exact same name + you can freeze the object.
      const UserRole = Object.freeze({
      User: 'user',
      Admin: 'admin',
      Staff: 'staff',
      } as const);
      type UserRole = ObjectValues;

    • @trontor.6711
      @trontor.6711 ปีที่แล้ว +1

      @@paulrukavishnikov5171 because you can't iterate over the values.

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

      @@trontor.6711 Object.values(YourEnum).map works perfectly

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

      enum UserRole {
      User = '0',
      Admin = '1',
      Staff = '2'
      }
      This works using an enum. the literal can be whatever you want it to be.
      iterating and key access of native enums.
      can use zod descrimated unions with them.
      Avoids the null value of the first element.

  • @ronbiton8799
    @ronbiton8799 ปีที่แล้ว +10

    It is a cool solution but you will be forced to deal with random strings located in random pieces of your application.
    You will not be able to use the list of enum values as you would with an enum.
    So a basic condition turns from this:
    if(user.role === UserRoles.Admin)
    // Which is not only type safe, but also allows for an easy change of either key or value
    to this:
    if(user.role === "Admin")
    // Which might still be type safe, in the sense that you won't be able to compare it to values that are not part of the type, but you loose some of the consistency an enum is giving you.
    I do have a fare share of problems with enum, but this will not be a good enough replacement for me.

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

    Enums with strings basically solves all the problems presented here

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

    Being a C coder, I really have no idea what the problem is that you're illustrating. I mean, *of course* User == 0. What am I missing???

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

      Checking for "if (SomeEnum.User))" will return false because "Boolean(0)" returns false too, so you cant properly check for truthiness here

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

      @@refinery__ If the goal is to check if SomeEnum.User has been set to something, that doesn't make any sense at all.
      Enums aren't objects/structs. They're constant values. Think of it like compiled code with #define USER 0. USER is a placeholder for 0, and you can't change the value of 0. So using an enum as an object is bad. I've seen the various examples posted by the TH-camr, but all of them lead back to that central conclusion: a misunderstanding of the purpose of enums, not that enums shouldn't be used.

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

      @@yapdog I think it's kind of a lacking example to do if(). Even in TS/JS it doesn't make sense to check "if value". (if value is what???) He should present it as if(value === ), but then you don't really have any issues with enums in general. Though in TS it's kind of a bad practice to set first enum as 0 cause it's falsy. It's easier on mind to just assign truthy valeus in enum, so you won't be bothered by potentials bugs with it, but it's still a matter of opinion tbf. I prefer to set enums with strings as values.

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

    enum UserRoles { User = 'user' }. This way, you avoid the problem. Have type safety, have dot syntax, and less code...

  • @Nil-js4bf
    @Nil-js4bf ปีที่แล้ว +6

    I use string literals and arrays as much as possible. String literals are nice in that you don't need to import it to use it as a value but it's a double edged sword because that also means you can't click the type to find all its usages.

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

    I'm not sure why you went with an array example, if someone can get away with using array as const they never needed that enum in the first place, object as const is usually what enums are substituted with to avoid "magic values" (I'd say the only thing enums have going for them is that they enforce enum symbol usage instead of literal value, which makes refactoring and reference finding much more reliable)
    const UserRole = {
    User: 'user',
    Admin: 'admin',
    Staff: 'staff',
    } as const;
    type UserRole = typeof UserRole[keyof typeof UserRole] // replace with utility type to reduce ugliness
    const USER_ROLES = Object.values(UserRole);

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

      Enums compiled into object. Why don’t to use enums then? They are semantically **enumerate**

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

      @@Disorrder Enums compile into objects with unwelcome additions that unnecessarily complicate things

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

      @@Disorrder You will actually notice that if you try to run Object.values() on enum with numeric values

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

      Enums are transpiled into IIFE's not objects (they are evaluated into objects at runtime) and are not tree-shakable unlike object literals. It will appear in the bundle, whether you use the enum or not.

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

    I like these short typescript videos, make more of them in the future, please!

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

      This particular video about enums is misleading. Don't take his advice.

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

      Please for the love of coding, don't follow his advice.

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

    I never liked the whole idea of typescript paradigms trying to shoehorn their way in to a valid JS construct at build time

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

      TypeScript doesn't like it either and the devs have expressed regret on adding anything that has runtime effects like enums & namespaces.

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

      Thankfully the TS team seems to agree and has stopped doing this

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

    This is not how enums are supposed to be used.
    They are not lists, you are not supposed to iterate through them or use them in conditional statements the way you showed.
    The main use of enums is to strongly type parameters, properties, and return values that represent sets of values.
    Using the UserRole example:
    enum UserRole {
    User,
    Admin,
    Staf
    }
    class User {
    name: string;
    role: UserRole;
    constructor(name: string, role: UserRole) {
    this.name = name;
    this.role = role;
    }
    }

    let exampleUser = new User("John", UserRole.User);
    if (exampleUser.role === UserRole.User){
    console.log("I am a regular user!")
    }
    Here we have a strongly typed field and we can compare it against it's possible values as opposed to using magic strings.
    Saying "It's so much easier to work with the values when you ignore the weird behaviors of enums by throwing them out entirely" in this situation is like trying to add "2" + "2", being surprised why the result is "22" and not "4", and then saying "It's so much easier to work with the values when you ignore the weird behaviors of strings by throwing them out entirely".
    Lets not throw out string or enums. Let's use the tools we have for the things they are designed to do.

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

    literally what I search yesterday.. it's crazy that you immediately roll out this video

  • @Retro.one4
    @Retro.one4 ปีที่แล้ว +5

    While I agree with you on typescript enums.
    With this method you lose the dot syntax for uses elsewhere. Say when you want to query Users.Admin you have to use User[1]. Using indexes is worse than not being able to iterate.
    I've been messing around with using objects and typeof keyof, Object.entities as a replacement for enums and and arrays, but this is a work in progress.

    • @theory-in-motion
      @theory-in-motion ปีที่แล้ว

      Doesn't need to be work in progress. It's the hands-down better way of doing things, 99% of the time, for things that could be enumerations or static config objects.

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

    love these types of short "hey heres a small piece of typescript you may want to rethink" as its much easier to digest small topics so i dont have to prepare to watch a long discussion with too much info for one sitting.

  • @Chris-Clicks
    @Chris-Clicks ปีที่แล้ว +7

    Just set the enum values to strings with the same name? Why would you create an enum without giving the options values (a string in most cases)?

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

      it helps with serialization too to use strings, instead of relying on your server side and client side be declared even in the same order

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

    At my company we had a huge chunk of code migrated out of a single code base to a shared component library. There was heavy use of enums and it’s awful. You try and mix types with your own app's and you always have to pull in enums from the shared library to make typescript happy. String unions solved the issue and makes things a lot nicer to work with. (Hint, its also whats used by all the large open source typescript projects)
    My recommendation is if you want to use enums, they should be isolated in your own module and not be exposed to others in your interfaces.

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

    Enums are amazing if you use them correctly. Which means with strings as values. Then you can amazing typings and values in your code
    enum UserRole {
    admin = 'admin',
    user = 'user'
    }
    if (user.role === UserRole.admin) // it's a valid check when user came from backend for example because we have a value and a type.
    interface UserInterface { // here is super confortable to use enum as a type.
    id: string;
    role: UserRole
    }

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

      It's a silly video to get our attention😄

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

    quick note: enums in my opinion are not meant to be used like that
    enums are suppose to be numbers that you can do bit operations on
    in this sense you should only use `const enum`
    and if you are using `enum` you probably not looking for enum and looking for:
    const Roles = ['admin', 'moderator', 'user'] as const
    type Role = typeof Roles[number]
    or
    const Roles = new Set(['admin', 'moderator', 'user'] as const)
    type Role = typeof Roles extends Set ? T : never

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

    Thank you!!! This works really well, I'm so glad you made a video about it.

  • @axeld.santacruz4659
    @axeld.santacruz4659 ปีที่แล้ว +1

    Me looking for this video, at 9:45 p.m. when doing some react. Good content, mate.

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

    I have to admit: this is really good stuff.

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

    one video id like to see about ts is all the interactions with data that comes from backend, or generally from outside the codebase.

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

    The array for iteration was super helpful - thanks!

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

    I like enums (come from Java land before getting job were no Java is required). I don't use em often, but I like using them say for quick example off the top of my head -- logging things (create enum of possible log types or whatever). I know they're many ways to avoid enums but that's the beauty of programming everyone has a preference to how they describe things.

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

    Why not just set your enum values to strings instead? That's what I do, solves these issues in a more elegant way imo. Plus, what is be the purpose of the expression:
    "If (UserRole.User) {}"
    Why would you ever write that? What is that meant to be accomplishing? If you're not explicitly checking for undefined/null on your literal types, then you're going to run into problems sooner or later when you come across a value of zero or an empty string. Besides, isn't it pretty common convention for numerical enum values to begin at zero unless otherwise initialized?

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

    String enums do not have those issues AND you can loop over their values, something you can't do with type literals (at least not straight forward) . Literal Types are great (e.g. Template literal types) but they do not replace all use cases for string enums. Also the DX is worse (imho) AND they disappear at runtime, while enums are just objects. Both have their uses.

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

      Enums are not just objects, they are compiled to IIFEs (immediately invoked function expressions), meaning that they add additional implicit overhead both in runtime, but also in bundle size shipped to users. IIFEs cannot be tree shaken because have to be invoked on initialization. So even unused enums will be end up being bundled, even if you aren't using them anywhere.
      Oh, but why not just use const enum then? Then they will be stripped away! In application code, sure if your entire codebase is 100% TypeScript, because there's no interopability between JavaScript, which cannot import or access const enums and have to use literal types, and TypeScript, which is required to use the enums due to its constraints.
      The solution? Unions. If you don't need the values at runtime, specify them as unions. If you need the iterate over the values, you can use a readonly array and get the type for each value as a union. If you really need to access them through dot notation, you can use a readonly object literal and get the types for each of the values. You can even name the type the same as the variable. Additionally, if you don't use the values in runtime anywhere, they won't be bundled, so they are essentially free.

  • @PhilipAlexanderHassialis
    @PhilipAlexanderHassialis ปีที่แล้ว +11

    Great, short and to the point Theo...
    but how about a followup with a enum UserRole = { User: USER, Staff: STAFF, Admin: ADMIN} with USER/STAFF/ADMIN being predefined const strings?
    If I recall correctly, past TS4.4. you can have this actually work for you in conditions and whatnot.
    P.S. Matt's video on enums was excellent.
    P.S.2: Who *in their right mind* actually do an if (an enum) and not if (check variable value vs enum)? Why are they allowed to do it more than once? :)

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

      if the property containing the enum is nullable maybe?

    • @t3dotgg
      @t3dotgg  ปีที่แล้ว +10

      This is just string literal types with extra steps

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

      @@omri9325 I believe in a case of UserRole, it’s impossible that the property would be nullable :)

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

      @@t3dotgg but but but my dot notation :)

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

    the main problem of Enums is when you change order you will have unexpected behaviors (value changed). I only use it with string values...

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

    typeof UserRoles[number] is so unintuitive. I believe It's more readible to use enums as collection of key value pairs with strings as values instead of implicitly assigned numbers that can be falsy as it's presented

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

    Yes! Here's my preferred replacement for Typescript enums:
    ```typescript
    const USER_ROLE = {
    USER: "user",
    ADMIN: "admin",
    STAFF: "staff"
    } as const;
    type UserRole = typeof USER_ROLE[keyof typeof USER_ROLE];
    ```
    It's still easy to iterate with `Object.keys()`, `Object.values()` or `Object.entries()`.

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

      Replace 'const USER_ROLE =' with 'enum UserRole', replace ':' with '= ', and delete 'as const;' and 'type UserRole...'

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

      @@NuncNuncNuncNunc why would I do that? Did you watch the video? The point is to *not* use Typescript enums.
      My code gives me everything I might want from enums while avoiding any surprising or unwanted behavior.

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

    You’re wrong. Typescripts enums aren’t great for sure, they are overly complex, but “bare string” solutions are just worse in every way.

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

    Thanks for the gift, finally, a YT link I can send the next time someone disagrees with me on Reddit over enums

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

    "What if we replace standard notation with non-standard notation but just all remember it and not rely on our build tools to do it for us?"
    What you've done here is replace a simple concept applicable in most languages with a hack that only works in some languages, in order to get some of the same behaviour. And you've polluted your namespace with duplicates of every enum in order to be able to enumerate over the possible values, and you've made the size of a user structure substantially larger by requiring the storage of an entire string where a short would've sufficed.
    This is bad advice and you should post a followup.

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

    that's an extremely bad example why enums are bad. If you need a string representation of the enum then i would accept it, but even then the proper solution is to have a procedural macro, just like rust, that generates the "to_string" implementation of an enum automatically.

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

    Thank you for continuing making short videos

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

    Great video! Used AoC to learn some TypeScript and I probably used an enum on half of the days in AoC. This makes perfect sense to me though.

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

    make more of these, I like them

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

    0:54 - Ok I don't like enums too but why would you ever do that

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

      const user = {id: 1, role: UserRole.User)
      if (!user.role) {
      user.role = UserRole.Unassigned
      }

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

      @@t3dotgg Ah, thanks, now I'm getting flashbacks

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

      Have you seen juniors or pretend "mid"'s code? You will be amazed at what you will see. Thoroughly amazed.

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

      ​@@t3dotgg If you ask me, that's a problem with TS's implementation, not with enums themselves. Also, I would say your code example is bad code. Put a type on user so role is UserRole or null and check explicitly for null. Lots of things in javascript are falsy, not just enum variants. I would also argue here that TS needs a better Option type.

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

      ​@@MarcelRobitaille That's exactly what he's saying, it's a problem with TS implementation, not enums in general
      If you start explicitly checking for null, you would also have to be explicitly checking for undefined
      Option type in typescript wouldn't make much sense, it's like trying to use only null or only undefined, external dependencies will mess everything up and making abstractions over them is just not worth the overhead

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

    I have seen a lot of videos about typescript enums being bad recently, it seems to be the flavour of youtube at the moment, but they all seem to skip over the fact that you can assign your own numeric or string values to the enum. is there any reason not to do the below to solve the problem you're talking about here? For what it's worth, i think the type syntax with string literals is still a better solution, but I feel like assigning your enums this way avoids a lot of the enum problems I have been seeing on youtube recently.
    enum UserRole {
    User=100,
    Admin=200,
    Staff=300
    }
    or
    enum UserRole {
    User="USER",
    Admin="ADMIN",
    Staff="STAFF"
    }

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

      Any video that claims Enums are bad without addressing this is clearly just a quick clickbait attempt. How can you possibly state the issues, when you completely ignore one of the basic features of the enum. Its just an argument in poor faith, as you said he's just jumped on the Enum bad bandwagon like a few other youtubers, I respect the hussle but not his strongest videos and makes me question some of the other videos ive taken his word for irt topics I know less about.

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

    Not a typescript user or JavaScript, but in every other language you can explicitly set the values of enums, this is great for parsing binary protocols as you can do stuff like
    switch(bytes.peek() as enum PacketType){
    case PacketType::A:
    break;
    case PacketType::B:
    break;
    ..etc..
    }
    Where the bytes.peek() is returning some binary value like 0xEB, and perhaps in your PacketType enum defines PacketType::B as 0xEB like the following:
    enum PacketType {
    A = 0x42,
    B = 0xEB,

    }
    Is this not a pattern that is possible in typescript?
    I imagine typescript’s enums are not so restrictive as to force enums to begin at 0 right?
    That kinda feels like a required feature all enums should have in every language, to be able to set a start value or just explicitly set every enum member value.

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

      Thanks!!!!!!

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

      You can explicitly set the value in JS as well and they seem to be ignoring that in the video

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

    Okay, so will admit I was really puzzled at first and was thinking this wasn't that big of a deal. I use Enums a lot and thought this was not that useful of a video, and that Enums are great and have been very useful, but after checking out the Video you recommended from Matt Polock, and deciding to pull back the layers of what TS is doing and what's actually happening when you're declaring an enum, I understand what you are getting at in this video. Just because something "works" doesn't mean that's a good way to do it, though also, if it does work, don't touch it. :)
    Anyone confused here, sure, you can use enum, obviously your code works, that's great, by all means keep doing you, but if you really want to improve, I suggest you pull back the TS layer and really dig into what's happening under the hood in JS. I'm looking at my Enums now a lot differently.

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

    I think Enums are actually useful. I prefer this instead of an array :
    enum UserRoles {
    Null_User,
    User,
    Admin,
    Staff,
    }
    if you don't like the Null_User one you can use an object instead ( suggested by other comments )

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

      Or
      enum UserRoles {
      User = 1,
      Admin,
      Staff,
      }

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

    Probably someone commented on this already. I agree with your point, but you should have mentioned string enums as well. What do you think about them? Thanks for the video!

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

    THANK YOU. I've been thinking about this for months.

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

      He gave examples of bad coding, not an example of why enumeration is bad

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

      @@yxngboypolo what?

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

      @@mosescosme8629 the example he gave her horrible. All he did was show how not to code

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

      @@yxngboypolo why bother me about it?

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

      @@mosescosme8629 u made a comment approving his messages, I made a comment disproving yours. That’s how the Internet works buddy.

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

    literally just put the word "const" before the enum keyword and now you keep the dot syntax but it's not a scuffed object anymore. I always use either `const enum` or `as const`, depending on if I need to iterate over the values (which I usually don't need if it's something I'd want to use an enum for) :)

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

    How about
    const UserRoles = {
    User: "User",
    Admin: "Admin",
    Staff: "Staff"
    } as const
    type UserRole = typeof UserRoles[keyof typeof UserRoles]
    Then you get best of both worlds - not use enums and still get dot notation

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

    These new TypeScript features are lit.
    "as const", "satisfies", ... We're living in good times :')
    I just need to make me remind them when I need them.

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

    In general you'd never try to iterate over an enum in let's say c or c++. It was not meant for that so you are correct in your usage but disingenuous by not including that you can set the initial options value to another number. In higher level languages it's kinda sugar for devs forms systems languages. It's like adding unions in JavaScript. It's useless.

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

    So. This is all avoided by initializing the first enum to 1.
    I'm not saying you should use enum. But seems simpler than the other solutions offered here.

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

    Love these ❤️ more please 🙏

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

    For real though... I was afraid to click because I hate enums so much. Thanks for changing the thumbnail

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

    Could you use an object instead of an array, then use `keyof` to declare the type? Then you could access like an enum, while also getting the type safety you're looking for.
    Also if I do use enum, I set the value like this to avoid the number issue:
    enum UserRole {
    Admin = 'Admin'
    }
    I prefer to use an object over enum so it can be used by js files if necessary. The array approach seems a little weird to me. I think I would prefer enum over that approach, using strings in the enum values of course.

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

    Good trick and I agree in general.
    As always the real world sometimes gets in the way when numbers really are needed and there really are a set few described e.g. by a specification. Example web socket close codes - I found myself declaring this enum recently
    enum WebSocketCodes {
    NORMAL_CLOSURE = 1000,
    GOING_AWAY = 1001,
    PROTOCOL_ERROR = 1002,
    ...
    }

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

    Isn't this how you are supposed to use an enum with strings? I would agree that it's silly that it defaults to numbers so that you have to define it like this, but it does allow for the original syntax plus the dot-reference.
    enum Direction {
    Up = "UP",
    Down = "DOWN"
    }

  • @headlights-go-up
    @headlights-go-up ปีที่แล้ว

    Short TS videos are so nice. 11/10

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

    This is the first video by Theo I didn't understand. It would have helped if it was longer and went into more depth with the given example. What if you start the enum at index of 1? What does line 3 do? Are enums going to be deprecated or changed in the future?

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

    I made a decision to stop using enums recently for similar reasons. They _seem_ right because they're in other languages like C++, but that doesn't mean they have the same use case in JavaScript land.

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

    So how do you do something like
    if (userFromServer.role === UserRoles.Admin) {doAdminStuff()} ?

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

    Refactoring enums is still easier than string literals, although TS enums are a real pain in the ass. The module export problem with them blows me away

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

      What's the module export problem?

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

    Changing a string literal value in one place might be a breaking change in 30,000 other places. But changing an enum's string initiation in one place will change it in all of the places it is used, and your developers will be able to more easily read your code.

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

    Similar things can be said about javascript as a whole, it's more about knowing what works and what not. Have been using string enums for years in really huge codebases and never had any issues

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

    You helped me realise why many people dislikes me.. I also talk big about these kinds of "standard knowledge" or Elon Musk. I mean you shouldn't, in general, but some people know what they are talking about.

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

    UserRole.User is a value of type UserRole. It is not a value of type Boolean. The problem you are facing here is not with TypeScript having a bad enum implementation, but with TypeScript being backwards compatible with JavaScript, which has a notion of "falsey" and "truthy" values instead of a hard requirement on only using Boolean values inside of conditionals. If you wrote the equivalent code to what you have written here in Rust, it would fail to compile because it expected a value of type bool and instead got a value of type UserRole. Instead of asking "if (user.role)" you should be asking "if (user.role === UserRole.User)". And as for your suggestion to define types as a union of strings, that is fundamentally cursed. Strings are not for storing categorical data. It's a bad practice in every other language, and it's a bad practice in TypeScript.

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

    I think the TypeScript static analyzer should make sure that developers aren't doing something incorrect like that if statement with enums. It simply doesn't make sense, it is checking a true/false state on the default value of an enum (the index of the enum itself) which hasn't been assigned a string literal or any boolean value. UserRole.User is a possible value for another value's state, NOT the state of a variable in and of itself.
    It's something that the C# compiler will warn you about, and C# enums work in the same way. The only reason this is passable in JavaScript (and not C#) is the semantics surrounding how JavaScript treats integer 0 and 1 numbers as booleans, and the index of the enum just so happens to be the same value of a JavaScript boolean.

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

    Constant/nonconstant variants are the best way to go about enums in my opinion, like OCaml or Rust. Enums either don't have any value associated with them or they do, and it is never a surprise. Pattern matching also makes them much easier to work with, which JS unfortunately doesn't have.

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

    enums are to define a static list of lookup items whose values never change. its subset to array containing static list of string literals. we use enums in java always and is much efficient than string array. define utility functions.. promotes single responsibility principle. maybe typescript hasnt matured enough to use enum efficiently.

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

      Maybe you should watch the video

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

    String enums are god tier, never use otherwise

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

    Enum can be key-value pair, i never use the default, it’s a bad practice. Esp you might remove or reorder things

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

      Enums protect you from reordering. Nothing change if you use enum values and reorder. But if you rely on their integer values it’s a bad practice.
      If you’re writing high performance code like 3d rendering, ordered enums might be helpful, since computer work with numbers faster than strings

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

    the solution is to not use enums in TS.
    A lot of languages the enums are hit or miss.
    Enums in Java are pretty good

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

    I would never use an enum (which is essentially a list of named integers in other languages) in a plain conditional.
    But if I really had no other choice, I would just do this: enum UserRole { Unassigned, User, Admin, Staff }
    It's really a matter of whether you know what you're doing or not, which I admit is much harder in JS. (Not sure if TS is any better at it)

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

    The only time I've used enums is in the context of using it in a c#-based backends with automated type generation.
    In C# an enum is always an int, so when we map it over its convenient also having an int so you can use it directly in the contract

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

    This is the content I subscribed for 👏

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

    You make some good points, but that's no excuse for how awful the enum implementation in typescript is. Sometimes enums really are the best pattern for a task. For example, you aren't blessed with tRPC and you have to give human names to integer variants that have to be consistent with your backend.

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

      That's when you use a plain js object with "const Obj = { /* Whatever would be in the enum */} as const" and then "type T = typeof Obj[keyof typeof Obj]" to generate a union type for it.

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

      @@JeyPeyy That's pretty much what TS is doing.

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

      Enum implementation is not that bad. That viral idea on TH-cam washed your brain. Someone started and other bloggers repeat

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

      @@MarcelRobitaille Not really. With this, the generated type is a union that can be extended as such and used in utility types etc. A problem with numeric Enums is also that you get all the reverse mappings thus it makes it really bad for iterating through the keys.

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

      @@Disorrder The typescript devs seem to agree though. It's far from the worst thing in the world of web development, but it's not good and there are better alternatives.

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

    Let's leave behind the strong clickbait opinions about how coders should develop behind in 2022.
    Generally, either string literals or enum with KEY = "KEY" both seem fine...
    String literals lose readability - `assign_role(user, "Admin")` is (imo) less readable than `assign_role(user, Role.ADMIN)` - is "Admin" a user-facing string? Typesafe? Part of some list of possible values? What is that list?
    They also sacrifice refactorability - good luck safely changing all occurrences of "Admin" to "SuperAdmin" in a large codebase.
    String literals are a bit easier to write since you don't need to import Role and you get autocomplete.
    But really, this is the kind of thing that just doesn't matter. There are some issues with string literals, and there are some issues with enums. Once you hit them once, you won't hit them again. Each developer/company has their own preferences that don't actually cause issues if stuck to consistently.
    And seriously, it's not like enums are a common source of bugs in any production code at least that I know of.. I don't know why it's become such a polarized topic lol

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

    You shouldn't rely on the boolean value of a numerical type either way though

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

    As a Python Pydantic fan I'm wondering how you feel about the Zod package. Getting Pydantic like validation in TS is a dream for a Python D4A specialist like me. For me it's always necessary to have an extremely strong validation library.

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

      I think he’s a fan, it’s used pretty heavily in the T3 CLI

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

      Zod is amazing, in typescript we use it a lot. And in trpc, zodios or t3stack is default for everything.

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

      He's a fan. He covers it in his other Typescript video "You might be using Typescript wrong"

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

    You are trying so hard to prove your point. :) Using only Enum’s value in an if condition doesn’t make sense at all. After that example, I stopped the video. Sorry. :)

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

      Yeah TS enums are bad for a number of reasons. The fact that an enum value can be 0 is not one of them 😂

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

    I like some of what I see in the comments.
    This video is utter crap.
    How dare you say enums is the worst TS feature. You certainly don't know how to use it best. 🙄
    I use enums a lot (exactly how someone, @Rick, described), and I don't see how your boilerplate-y code is better than enums. Utter crap.🙄
    I could iterate through an enum, use it as a (string constant) type and use its values as well (like an object just as your boilerplate-y code showed) and the DX is way better than yours.
    You should not talk about a feature if you're not really sure how it works. Do your research well before coming out at us. 🙄

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

    You should check if it is the int value or if you really want you can add "default" for the first index of the enum and then your first item is > 0. I think that would be a much simpler usage. The problem is using a sudo typed language you can pick how type strict you want to be, which can be confusing to some.

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

    Ok, what about this:
    enum UserRoles {
    User=1,
    Something,
    SomethingElse,
    Etc,
    }
    Isn't that the easiest way to do things? It solves the problem and allows you to use the same readable syntax of enums

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

      Then someone comes along and reorders the list and you've now got hard-to-debug bugs in your code. If you absoluty need to use an enum, use explicit strings because they will also show up when debugging, rather than some arbitrary number.

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

    Quite interesting video, I’ve never worked with Typescript, and I’ve the question.
    Can we use typescript enums say to do data validation?
    As one might do for example in python.
    assert UserRoles(“your value”), ‘role doesn’t exist’

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

    Looks to me like typescript is just way too lenient with allowing all types in an if statement. You are a typed language, why not only allow booleans?

  • @dan-kn3dm
    @dan-kn3dm ปีที่แล้ว

    I find numeric enums useful when I want to retrieve the enum index number by using the enum itself. The suggested approach wouldn't work in this case without calling .indexOf on the array of strings every single time, which is wordier and less performant.

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

      Using the indexes is even more cursed because you might add a new value to the enum and break the stored state

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

    export type Values = T[keyof T];
    export const MyEnum = {
    FOO: 'FOO',
    BAR: 'BAR
    } as const;
    export type MyEnum = Values;
    You're welcome

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

    I have seen a use of enums as constants. The alternative is a JS/TS object `const constants = { KEY: 'VALUE' }`.
    What do you suggest for these cases?

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

    He is correct that Enums aren't the best way to store data, but this also isn't the best example of how to properly use enums.

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

    why not use an enum like that:
    enum UserRole{
    USER = 'User',
    ADMIN = 'Admin'...
    }
    then you get a value- not an incumbent number when u use UserRole.ADMIN...

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

    I like it keep them coming plz

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

    I mostly use enums to store repeated string values.

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

    Numeric enums are legitimately problematic, but string enums just work as expected. Switching to bare strings loses the DX of having an easily accessible set of constrained values. I completely get the hate on numeric enums (and to be honest they can be problematic in other languages as well), but string enums, I'm still failing to see the real problem, and they offer some good benefits vs the alternatives.
    All of these issues would be solved with a lint rule blocking numeric enums.

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

    That's so funny. Enums in c work kinda similar, the difference is that you cannot assign something else rather than numbers as values in enums, but still they are so loved. I do not understand why the almost same thing in ts does not satisfy developers. Maybe I'm misunderstanding something, correct me if so.