Enums considered harmful

  Рет қаралды 210,547

Matt Pocock

Matt Pocock

Күн бұрын

Пікірлер: 507
@mattpocockuk
@mattpocockuk Жыл бұрын
Forgot to mention in the video, but union types are great alternative to const enums. Want your code to disappear at runtime? Don't need an object representation? Just use a union of strings: type LogLevel = 'DEBUG' | 'WARNING' | 'ERROR';
@sachahjkl
@sachahjkl Жыл бұрын
const LogLevels = ["DEBUG", "INFO", "WARNING", "ERROR"] as const; type LogLevel = typeof LogLevels[number]
@mattpocockuk
@mattpocockuk Жыл бұрын
@@sachahjkl Yes, also a great case. Although LogLevels.includes is annoying.
@wlockuz4467
@wlockuz4467 Жыл бұрын
Was about to point this out haha
@littlesandra87
@littlesandra87 Жыл бұрын
Does there exist a way to have ESLint or similar give an error if the code contains enums?
@arunsp767
@arunsp767 Жыл бұрын
Oh ya, I use this most of the time. I was wondering do we really need enums? Now I know why I thought that 🙂
@oleksandrfomin326
@oleksandrfomin326 Жыл бұрын
Enums have worked great for me. Readability and robustness that they introduce outweigh the potential pitfalls IMO. In fact, I've never even run into problems discussed in the video myself
@Slashx92
@Slashx92 Жыл бұрын
I did run into problems like having to filter out keys of an enum if it were a number, but only because I was abusing enums to register categories instead of representing the categories as data
@Slashx92
@Slashx92 Жыл бұрын
@@austinmajeski9427 yeah it's both of those things. I did that in a proof of concept for myself tho, I usually don't allow myself to be that "creative" if I'm working for a client lol. And I eventually just converted them to objects, since it was data all along
@diego-aquino
@diego-aquino Жыл бұрын
Me too. Many times I had to change union type values and I would have to replace each occurrence in the entire project, while refaforing enums is extremely easy. I also like that TypeScript prevents you from using the enum values directly, as this would negate all benefits of abstracting their values in the first place over union types.
@cytherea165
@cytherea165 Жыл бұрын
I agree. If you stick to assigning strings to the enum keys, you avoid all the issues Matt describes. And I actually like that enums force you to write out Enum.Key instead of allowing the use of plain strings (like in string union type) as this makes for much better code maintenance in the long run (if the value changes in the future, you just need to change it in one place). @Matt Pocock, I love your content, but here I really disagree with you. I was expecting a strong case against enums, but I don't see one.
@ThisAintMyGithub
@ThisAintMyGithub Жыл бұрын
I've also been nothing but happy with Enums. The refactor-ability of Enums make a world of difference
@artu-hnrq
@artu-hnrq Жыл бұрын
My Typescript understanding has improved a lot since I started to watch your videos, Matt. Thanks for that
@object_name
@object_name Жыл бұрын
I have to disagree. After watching the video i feel like i prefer Enums the way they are in Typescript, than what you proposed. Not that i have not messed it up once or twice before, but i think, as you said, i would really dislike allowing strings in places where i require an enum. It's the reason i use the enums in the first place. In most cases you are also not supposed to dereference enums, i would say.
@Scuubie
@Scuubie Жыл бұрын
Additionally the use case shown from 6:16 does work the same with enums if you assign the strings to the keys. Using enums instead of strings makes it also way easier to rename the keys or values.
@snnsnn
@snnsnn Жыл бұрын
Also using zero based unions of numbers prone to bugs due to being falsy.
@iamstickfigure
@iamstickfigure Жыл бұрын
@@Scuubie Yeah.... I found it pretty annoying that he made it seem like a label map is required at 7:19. Like, he already showed earlier in the video that you can use strings as values for the enums. And doing so eliminates every problem mentioned in the video. The only "problem" it doesn't solve is that it doesn't let you use strings instead of the enum, which I think is actually a good thing. I found the majority of the video to be a really bad take overall. Also, the thing with LogLevel and LogLevel2 at 3:50 is just ridiculous. If you end up in a situation where you have two different enums that represent similar states, it was either a mistake that could be refactored, or there's an important distinction, or each enum is from a different code library. In any case, if you find yourself in this situation and can't refactor your way out of it, "just using the string values" is like the worst choice you could make. Lol. Most likely, the right decision would be to have some function that converts one enum to the other. Even if you're using the "as const" thing, using the string values on their own just seems like a bad idea
@Scuubie
@Scuubie Жыл бұрын
@@iamstickfigure and if you wanna use strings in your code, just use a union type.
@n00dle_king
@n00dle_king Жыл бұрын
Yeah I’d absolutely reject a PR that uses strings and “enums” interchangeably it’s not maintainable and reeks of the sort of thing you’d do in a small single developer codebase because you think you can remember all your cute tricks a year later.
@ThijmenCodes
@ThijmenCodes Жыл бұрын
Hey Matt, I like how you express yourself. Well-paced and with plenty of depth without getting long-winded. Awesome!
@markovujanic
@markovujanic 3 ай бұрын
Thanks Matt, I shared this video with multiple people already, I knew enums are problematic but didn't really know why, you did great job making me understand. The way you plugged your payed course is perfectly done and I hope other from industry are taking notes.
@jandurek
@jandurek Жыл бұрын
Honestly the fact that enums aren't just structural is an advantage to me. The main point of using enums is that you use enums and not strings. String enums have the best behaviour out of all the options mentioned.
@MrTruthAndFacts
@MrTruthAndFacts Жыл бұрын
The best thing about the content of this channel is that they're short, succinct but massively useful. Much better than watching a 60 minutes presentation
@mattpocockuk
@mattpocockuk Жыл бұрын
Thanks pal! I thought I rambled a bit in this one by my standards.
@driden1987
@driden1987 Жыл бұрын
+1 they are compact filled with knowledge. It’s probably the best format for a KZbin video ❤
@aduad
@aduad Жыл бұрын
2:25 I don't think this defeats the purpose of enums and in fact should be the recommended way of using enums since it mirrors the const object. I find you don't want to ever allow bare strings as values that as supposed to be mapped to a specific thing...makes refactoring much harder...and I also make it a rule not to look at compiled code and stick to the actual source. I use enums like this: enum LogLevelEnum { debug = 'DEBUG', warning = 'WARNING', error = 'ERROR', } type LogKeys = keyof typeof LogLevelEnum; type LogLevel = typeof LogLevelEnum[LogKeys]; let logLevel: LogLevel = LogLevelEnum.debug;
@iamstickfigure
@iamstickfigure Жыл бұрын
Yeah, the thing he said about it defeating the purpose of an enum was incredibly silly and nonsensical. Especially since his recommended method involves making a POJO with strings as the values anyway. Lol. It's basically the exact same thing, but the only difference is that his method requires a ton of boilerplate, and it allows people to use strings instead of the enum, which, as you also pointed out, is a really terrible idea. Lol. I really do not understand the point of this video other than to warn people not to declare bare enums that auto-define number values. That is a useful thing that I learned from this video. Everything else seemed like it wasn't thought through very well....
@envo2199
@envo2199 Жыл бұрын
did you use enums in a proper language like c#? He is right, it is not how an enum should behave.
@RegalWK
@RegalWK Жыл бұрын
you can just type. enum LogLevelEnum { debug = 'DEBUG', warning = 'WARNING', error = 'ERROR', } let logLevel: LogLevelEnum = LogLevelEnum.debug
@josedallasta
@josedallasta Жыл бұрын
i have different opinions on TS enums: 1- i think (like you said) the enums are the best option for code refactoring, and a great solution for keeping values throughout your code base the same. (when you change the values in one place, they change in every place the enum is used, if you just pass arguments from an enum, but as just strings, you will need to change every place that value is used); 2- about the thing that you shouldn't be explicit when using enums, because it sort of defeats it's purpose, i 100% agree with that, but i also think being explicit is way better than implicit, because someone may change the order of variables (in a conflict from merging, for example) and change it's values, or is just too inexperienced and mess something up; 3- (and this is about everything in transpiled JS) about the way it is done in javascript when transpiled, i think if it performs great, do it's job without problems and will not be a problem for the developers and users in the future, it shouldn't be something you care that much about, because you will not see this code, what you see/code is TS, the JS is just runned by the engine.
@gamechannel1271
@gamechannel1271 Жыл бұрын
#2 only matters if you ever do any operation the checks or stores/reads the numeric value of the enum explicitly.
@MenelBOT
@MenelBOT Жыл бұрын
ran*
@duro6969
@duro6969 Жыл бұрын
If you'd like to allow the string representation of the enum you can do something similar enum LogLevel { DEBUG = 'DEBUG', WARNING = 'WARNING', ERROR = 'ERROR', } function log(message: string, level: LogLevel | `${LogLevel}`) { } log('Hello!', LogLevel.DEBUG); // Works log('Hello!', 'DEBUG'); // Also works
@dealloc
@dealloc Жыл бұрын
Yep. This makes enums even more pointless than they already are. One could argue that invariance is good-in that two different enum types with same value should not be considered the same-although I myself disagree this is a good thing, because "DEBUG" is "DEBUG" is "DEBUG". Always. But in your example the enum is now just overhead (emitted code + leaky abstraction). I could see this as being a good way to introduce temporary types in order to refactor _away_ from enums, so to stay compatible with existing code while also forwards compatible with unions. Good thing!
@williamdrum9899
@williamdrum9899 Жыл бұрын
Why weren't enums just a nickname that the compiler replaces with the number at compile time?
@dealloc
@dealloc Жыл бұрын
@@williamdrum9899 You can with const enum, but those are even more terrible for consumers that use JavaScript, because they have the same constraints as enum but aren't accessible by JavaScript.
@rcnhsuailsnyfiue2
@rcnhsuailsnyfiue2 Жыл бұрын
This defeats the point of enums. Enums are *not* strings, they represent states. The states they represent can be “backed by” strings, but a string “DEBUG” is NOT the same as an enum with a key called DEBUG.
@orlantquijada
@orlantquijada Жыл бұрын
commenting to support the channel. loving the content lately, hopefully more to come!
@Joso997
@Joso997 Жыл бұрын
I am using enums for my whole framework. They are perfectly fine
@tomasburian6550
@tomasburian6550 3 ай бұрын
Using POJO is always my preferred way to go now. Great video!
@tunoajohnson256
@tunoajohnson256 Жыл бұрын
Gonna make a few dot points to try understand what youre saying - 1. Enums, when compiled, map in both direction. Meaning if you are treating it like an object, you will have extra key: value pairs that you need to expect. 2. Typescript cares about the Names of Enums. You cant use the Values of the enums in place of the name of the enum. 3. A neat alternative can be either Union Types or Const Object 4. Const Object together with ObjectValues type has the benefit of being able to use the Name or value of the item. Benefits of Enums naming without the above two issues. 5. Another Benefit is having the Object have a machine readable key, with a human readable representation of the key as the value. Thanks for the tips! :)
@_danyg_
@_danyg_ Жыл бұрын
BE AWARE: 1. Don't treat them as Objects, treat thems as Enums, maybe read how enums works in other languages to grasp the concept, maybe Java or C# or python, if you need to treat them as object, maybe are not enums or you need an extra map to define what you actually need. 2. if my data object has a propery call state, and its value is @ to define that is 'pending' (coming from backend) I can create a enum PENDING='@' and then check for obj.state === MyEnum.PENDING, if backend changes this to a string 'pending', I change the value of the enum and my code continue working. The concept of Pending still there, my code still readable, and the implementation of how pending is is protected by the enum. 3. This create problems when you try to create a list of values in a whitelist, you MUST typed the array that will contain those values, as ObjectValues[], using enums you don't need to because TS can infer it. The same happen every time you need to use that ConstEnum you need to specify that you require the values, at the end you endup exporting a MyContEnumValues then you are using 2 types for 1 enum, values and the map access to those values... is messy 4. Value of the enum shouldn't be used, if you need to use the Value then your abstraction is wrong somewhere, that value is representing somethign that you are not naming or/and your code is not specifing as necessary. 5. This is a given in enums enum States { Pending='%wait%' // Human readable = machine value, which you as developer shound't care how is even called. }
@tunoajohnson256
@tunoajohnson256 Жыл бұрын
@@_danyg_ Good stuff, I like the outlook. Thanks for sharing
@iterativeincremental
@iterativeincremental Жыл бұрын
without the re-enacting of 'hey maccarena' by the hands: One of the better instructional videos on ts i have seen.
@rcnhsuailsnyfiue2
@rcnhsuailsnyfiue2 Жыл бұрын
3:13 the point of an enum is *not* to represent a value, but a state. That’s why it’s not as straightforward as just passing the string “DEBUG”, because enums are not strings. Their values can be *backed by* strings, but their values are predefined and not variable. Enums act like their own types, and an arbitrary string can never be the same type as an enum whose value is backed by a string.
@armanrozika
@armanrozika Ай бұрын
this is what can't get into my head still, that i should treat enums like it's not a value assignment, it's already its own value. Arghhh, the very first thing i learned in javascript is that everything is an assignment, now this enums thing became hard to understand
@MattiHaapamaki
@MattiHaapamaki Жыл бұрын
Here's me again coming to one of your videos with a PR in with the exact thing you tell not to do. Thanks for your content! And definitely important to ask for the like as well. I would never remember to do it otherwise.
@Mi2ey
@Mi2ey Жыл бұрын
I can see the value in some of the solutions outlined in this video, but the one thing I find most useful about using enums is when working in a larger dev departments. Especially if some of the code may at some point be touched or viewed by members of other teams. It keeps uniformity in how you pass certain values, easy to check the available options with minimal code, and makes it easy to look up where it is used within a project. I like the as const approach, but I can't say that the arguments here against enums at least for most of my use cases justify a change in convention within a stable, well performing and large codebase. Nevertheless, the information is great to know and offers fantastic insights into the inner workings of TS!
@paulsanchez5030
@paulsanchez5030 Жыл бұрын
Great vid. I have to acknowledge. Javascript may be one of those lands that are a bit odd in some implementations., but it is one of the most satisfying languages to learn. I still enjoy how much I can easily do with it.
@mahmutjomaa6345
@mahmutjomaa6345 Жыл бұрын
Actually you don't need different names for const asserted enums and their type. You can have "const LogLevel = { ... } as const;" and "type LogLevel = ObjectValues;" in the same file. That's basically how @prisma/client generates enums from the schema.
@Вася-о3ф7ь
@Вася-о3ф7ь Жыл бұрын
Unfortunately, this is not perfect. The problem arises if you want to use "LogLevel.Debug" as a type, but are already importing both the type and the object. With enums it would be "type DebugMessage = { level: LogLevel.Debug; message: string; }". With as const typescript won't let you, so you'll need to write "type DebugMessage = { level: typeof LogLevel.Debug; message: string; }".
@mahmutjomaa6345
@mahmutjomaa6345 Жыл бұрын
@@Вася-о3ф7ь Good point. You can "import type" and rename the import in such rare case where you import both and need to distinguish between type and const.
@Daysalin
@Daysalin 3 ай бұрын
Love it
@duke605
@duke605 Жыл бұрын
Enums made me waste a few days trying to figure out why my tree shaking was not working. It was cause enums. When the bundler goes through, it sees the self invoking function as a side effect and includes it no matter what.
@RyanTipps
@RyanTipps Жыл бұрын
such an underrated channel - thank you so much!
@NuncNuncNuncNunc
@NuncNuncNuncNunc Жыл бұрын
A lot of the things you call weird are safeguards. Passing some random string as typed enum argument should always be an error. Do you want someone to pass in 'debug' when there will be a comparison against 'DEBUG'? You say breaking the rules, I say following the rules. Literals are almost always a code smell in my book. An ability to exchange enums is asking for trouble. @6:47 you've just rewritten enums that use '=' syntax as a const and made the string formatting more verbose.
@kumailn7662
@kumailn7662 Жыл бұрын
right, what you said i have the similar thoughts while listening to the video.
@JonathanRose24
@JonathanRose24 10 ай бұрын
But the values of the string literals are still type checked. You can't pass any string literal that isnt allowed. So if you are only allowing 'DEBUG' and you pass 'debug' it will be an error
@NuncNuncNuncNunc
@NuncNuncNuncNunc 10 ай бұрын
@@JonathanRose24 Here's a small demo of enum being "stronger" than literal function litfun(flag: LitFlag) { .... } function efun(flag: EnumFlag) {...} if both have "debug" in their type, you can pass EnumFlag's "debug" to litfun, but you can't pass literal "debug" to efun. Example is contrived, but the point is to show that sometime you want an explicit type, not just a string that happens to match.
@JonathanRose24
@JonathanRose24 10 ай бұрын
@@NuncNuncNuncNunc ok but how’s this a benefit? To me this is a negative as pointed out in the video because it works differently than how types work for everything else, that being structural typing. I guess where we differ is that I see no value in this explicit type.
@NuncNuncNuncNunc
@NuncNuncNuncNunc 10 ай бұрын
​@@JonathanRose24 Then it is a matter of preference. We're stuck with typescript comparing shape instead of type. My preference is for type checking. With respect typing, some use branded/tagged types to get better type safety. NgRx Actions feel like a proto version of this pattern. It's a pain having to do runtime type checks, but it's the best the language allows. PS I use both literals and enums where I feel appropriate, so this is not a dogmatic position.
@whitefluffycloud
@whitefluffycloud Жыл бұрын
Thanks for explaining the IIFE joke to us. That totally made it much better... XD
@ОлександрМельничук-с2т
@ОлександрМельничук-с2т Жыл бұрын
It seems that most people here do not read books for beginners, and therefore do not understand what this thing is and what enum is used for. Don't blame the microscope for not being good at hammering the nails. Read about enum flags, clean code, incapsulation and typescript implementation (what's going on behind the curtains)
@coolemur976
@coolemur976 Жыл бұрын
Enums all the way in big scale projects. You don't want to refactor hardcoded strings. Expression like log('Hey', 'DEBUG') is more harmful than log('Hey', LogLevel.DEBUG). (Unless you don't care about the future of your project)
@Dxpress_
@Dxpress_ Жыл бұрын
In other languages I'd agree, however in TypeScript, you don't have to use "string" type parameters as an alternative; you can explicitly define a constant set of string values as a unique type, and pass in that type as a function parameter instead. type LogLevel = 'DEBUG' | 'WARNING' | 'ERROR'; function log(message: string, level: LogLevel) { } log('Hello', 'DEBUG'); // OK. log('Hello', 'ABC'); // Immediate compile-time error. This still has all the compile-time & refactoring benefits as enums. In VSCode, you can refactor/rename any value of the type and have it be updated everywhere its used like usual. As you're inputting parameters for functions, Intellisense will suggest only the valid values that can be used like usual. If you input anything that's not one of the valid defined values for the type, you get a compile-time type-matching error like usual.
@coolemur976
@coolemur976 Жыл бұрын
@@Dxpress_ Sadly no, it doesn't replace all occurrences when you rename literal type.
@Dxpress_
@Dxpress_ Жыл бұрын
​@@coolemur976 Where does it not replace occurrences? I just tried it now and it seems to work fine.
@coolemur976
@coolemur976 Жыл бұрын
@@Dxpress_ I just tried it and it didn't replace some occurrences in React component prop. Moreover, when I search "find all references" by given literal type, it finds strings that doesn't belong to type being searched. Enums are much safer for refactoring.
@Dxpress_
@Dxpress_ Жыл бұрын
@@coolemur976 Aye, fair enough then.
@v23452
@v23452 6 күн бұрын
If I could give you 2 thumbs up, I would! Very cool, and I literally spent a day searching this information! So, lucky me :) PS It's a pity I won't be able to buy your course
@therufa
@therufa Жыл бұрын
i like the `keyof typeof` solution the most ❤ it's just so simple and versatile. Nice vod!
@robx_001
@robx_001 Жыл бұрын
very rarely such quality content
@benjidaniel5595
@benjidaniel5595 Жыл бұрын
Your representation of how to achieve the same result as an enum at 7:11 was a little uncharitable imho, as you could have simply written: ``` enum LogLevel { DEBUG = 'Debug', WARNING = 'Warning', ERROR = 'Error', } function log(message: string, level: LogLevel) { console.log(`${level}: ${message}`); } log('Hey', LogLevel.DEBUG) ``` Which is almost identical to using a constant object literal. I've never had an issue with enums when the values are strings
@saliabbasraza
@saliabbasraza 5 күн бұрын
i'm new to typescript and since i'm Java, enum doesn't look weird to me. I only respond to Matt question where he used string literal to pass as an argument to function, he said this looks more natural to javascript. What i understand this argument only makes sense if the argument we're passing is coming as variable that we need to pass as an argument. b/c otherwise if we're typing it doesn't matter if we type 'DEBUG' or LogLevel.DEBUG. So in case if it's coming as variable we can simply use as let logValue = 'DEBUG' printLogLevel(logValue as LOG_LEVEL) since i'm new to typescript, do let me know what you guys think.
@pw4827
@pw4827 Жыл бұрын
Waiting for the next video "Don't use letters! They can be harmful"
@fb1nhk3
@fb1nhk3 Жыл бұрын
Great explanation and nice video! I will still be using them though 😄 Working in a team the solution with "as const" and "typeof keyof" just seems a little too confusing. Plus I do not see the described flaws ever matter in a project where enums are used to define some values that would otherwise be hardcoded somewhere in the project
@KevinBoosten
@KevinBoosten Жыл бұрын
IIFE 🤣. Great video again! And completely agree with you that enums add little value (but more size) to your codebase 🎉
@yiluan6133
@yiluan6133 Жыл бұрын
3:13 Apologies for saying this but to me this is totally not weird. This is the EXACT reason why you use enum. You can't use some random string that happens to be "DEBUG" to equate to LogLevel.DEBUG, that's the whole point of using enum. I don't want someone passes, for example, ReportLevel.DEBUG to my logging function when what I really needed is a LogLevel enum, if there is a code that someone passes a wrong type of variable into a function, like this one, I want my compiler to tell me. I think If you've used C/C++ this behavior should be very natural to you.
@jeffrbake
@jeffrbake Жыл бұрын
I think saying "don't use enums" is incorrect. I use them, and all of the "weird" things you mentioned I make use of. But I would agree that you shouldn't use enums if you don't fully understand how they work.
@StuartLoria
@StuartLoria 8 ай бұрын
His british-english is american-english friendly, and he makes things clear, which is a first from a skinny smart guy, well done Sir.
@David-oc8yt
@David-oc8yt 8 ай бұрын
Coming from a C++ background, and given the described potential security issues with const, I much prefer the default implementation (non-const enum)
@BoscoDomingo-dy8kh
@BoscoDomingo-dy8kh 4 ай бұрын
Great video, but everything you mentioned in the video you can still achieve with enums: enum Enum2 { key0 = "0", key1 = "1" } // Which allows for type Enum2Keys = keyof typeof Enum2 // "key0" | "key1" type Enum2Values = `${Enum2}` // "0" | "1" function example(key: Enum2Keys, value: Enum2Values): void { //... } // Intelisense works in both of these, just like in your video example("key0", Enum2.key0); example("key1", "1"); I agree with not using number-based enums. Those are atrocious. But text-based? They are awesome and work incredibly well
@geisonmachadowork
@geisonmachadowork Жыл бұрын
5:44 this looks wrong, passing the enum value feels more static and less "magic" string, also if you've never saw it you have to stop and try to understand the two lines of code above it, seems an overkill for a non existent problem just for the sake of feeling clever.
@JelleJelleJelle
@JelleJelleJelle Жыл бұрын
I don't agree with the general take of this video. If you use enums with string values, such as enum LogLevel { DEBUG: 'Debug', WARN: 'Warn', ... }, you have best of both worlds: strictness and predictability. I think the "as const" approach defeats the purpose, because you shouldn't want to pass the value of the enum, because you shouldn't be interested in the value, but only what it represents, i.e. LogLevel.DEBUG makes sense, but whether its value is 'DEBUG', 'debug', 'Debug', or 'dEbUg', I really shouldn't care.
@personalgamedevyt9830
@personalgamedevyt9830 Жыл бұрын
I'm glad to watch videos like this and see good points, but ones that I don't 100% agree on. The are many ways to problem solve and it's interesting seeing other ways.
@yolamontalvan9502
@yolamontalvan9502 Жыл бұрын
Professor, This what I was looking for. Thanks. I subscribed.
@olduniverse9270
@olduniverse9270 Жыл бұрын
6:34 the little problem with this example, in my opinion, is if you didn't write a log function and just want to use it, you have no idea that you can use LOG_LEVEL object keys as an argument. You see a type LogLevel, maybe you tried to open a quote and realized that you can use some string values. But you should go to LogLevel declaration to see that this type is keys of object, so you can use this object. But I use this approach too.
@sona5704
@sona5704 Жыл бұрын
As a solo programmer yes, as const is the way to go. As an enterprise developer on a team of many teams, no import that enum cause trying to explain all this to a new dev that will get replaced next year is way too hard
@andrueanderson8637
@andrueanderson8637 Жыл бұрын
Yikes. I feel sorry for you for the caliber of developer you apparently work with that can't grasp the basics of types. Why bother using TypeScript?
@xbsidesx
@xbsidesx Жыл бұрын
Nice, your approach explaining things is really objective and I love the pacing of the whole video. Thank you!
@paxdriver
@paxdriver 3 ай бұрын
@2:35 that joke deserves an Awad award... Named after KZbin's world famous Ben Awad, of course.
@pythooonuser
@pythooonuser 4 ай бұрын
Regarding that "refactor in VS Code" argument: You can now refactor types, type members when they are strings. That's like 🤯
@jimmycat7774
@jimmycat7774 11 ай бұрын
Enums have worked great for me. The readability and robustness that they introduce outweigh the potential pitfalls IMO. In fact, I've never even run into problems discussed in the video myself
@thiagoalmeida5437
@thiagoalmeida5437 Жыл бұрын
Interesting discussion, some of points that I like about "number" enums: - Ability to do: if (currentLogLevel >= LogLevel.INFO)... - Ability to group things: if(currentLogLevel = LogLevel.WARN)... - Small serialization footprint
@yolamontalvan9502
@yolamontalvan9502 Жыл бұрын
I usually use const in upper case to create words used as words in C+. Works for me. In C#, I use enums.
@petarkolev6928
@petarkolev6928 Жыл бұрын
Omg, "as const" really sounds as a killer :O Thank you, Matt!!!!!!!!!!!!
@JamesQQuick
@JamesQQuick 8 ай бұрын
Great video!
@BoulderBrow
@BoulderBrow Жыл бұрын
A trivial point and it may be my editor theme, but I like being able to distinguish between an enum, object and string by their color.
@MrJester831
@MrJester831 Жыл бұрын
It's regrettable how awful TS enums are, not only for the quirks covered in this video, but also because of the missed opportunity to be an algebraic data type. Over in Rust land enums are quite powerful, not only in their ability to express variants of many types, but also in the way in which they can be comprehensively matched over and in how serialization/deserialization behavior can be derived and annotated as to also support things like tagged types. Error and Result enums are both incredibly useful
@cat-.-
@cat-.- Жыл бұрын
How would you reconcile an ADT concept with duck typing though? enum Result { Ok(T); Error(E) } // how do you think this should be compiled to JS?
@scheimong
@scheimong Жыл бұрын
Don't blame TS for this, blame JS. It's difficult to build something good on top of an "embarrassing toy language". Rubbish in, Rubbish out.
@MrJester831
@MrJester831 Жыл бұрын
@@scheimong there's nothing about JS that prevents TS from having good enums, TS just is weak sauce
@PeterAuto1
@PeterAuto1 Жыл бұрын
​@@cat-.- simply as a Tagged Union Ok(1) = { tag: "Ok", val: 1} Err("failure") = { tag: "Err", val: "failure"}
@alguienmasraro915
@alguienmasraro915 Жыл бұрын
Enums are not awful. You just don't know what their use is for.
@raizenpk
@raizenpk Жыл бұрын
We've been using enums extensively in our project and they are a great feature of TS in my opinion. We have predefined API values, let's say 'TEMPERATURE' or whatever. I think it's rather ugly to pass in 'TEMPERATURE', instead of, say Unit.Temperature, which is mapped to the literal string value. The API guys can do whatever they want, but our code remains nice and readable as Unit.Temperature, even if they rename it to 'TEMP' or 'TEMP_FAHRENHEIT' or 'tEmprATurrr'. Also, regarding your point about using the value directly, you can simply do type Units = `${Unit}`. It's not ideal, and I don't know why they don't allow the literal value by default.. but it is what it is.
@jtw-r
@jtw-r Жыл бұрын
ok … i’ve unknowingly run into this problem before, and also came to the conclusion that enums can product slightly less readable code (the double access). only occurred once or twice.
@nbaua3454
@nbaua3454 Жыл бұрын
Nicely explained.. I'm looking forward for more on typescript from you..and yeah I want you to have your mustache back as well..😉
@ElPolemista
@ElPolemista Ай бұрын
You could avoid "as const" TS syntax and keep the typing by creating a function that returns the constant object
@윤지만-w4m
@윤지만-w4m Жыл бұрын
Enums are a really good option if you want to use them without giving the user control over enums. Personally, the level of refactoring of the code is different. Needless to say, intuitive People around you see this kind of video and tell me not to use enum. However, if you ask them to implement the problem in the current code, not in a video or tutorial, they can't say anything.
@HenriKellock
@HenriKellock 10 ай бұрын
Thanks for the video! I personally use a lot of typescript enums but I still liked this video. After listening to this, I would also be fine with a code base lacking enums and using e.g. { ... } as const instead.
@aprilmintacpineda2713
@aprilmintacpineda2713 Жыл бұрын
I would just use a string literal for that, like, “debug” | “warn” etc
@switzerland
@switzerland Жыл бұрын
Oh wow, that why I had such an initial pain with TS, that explains a lot 😮
@blakeingle8922
@blakeingle8922 Жыл бұрын
Hard disagree. Using enums with manually assigned string values is the essence of what an enum is. It's just a complete list (an enumerated list.) Mapping values is a separate and entirely different toolkit in programming and it is convenient that it can be applied to TS enums. What you basically have uncovered is that "mapping" is a swiss army knife and "enums" is a hammer on the tool belt of programming.
@user-rp9iis1en6h
@user-rp9iis1en6h 10 ай бұрын
You are right. Enum is just a tool to make the code base more organized, give a quick summary of all possible values for a particular property. That's all. Why does he making it such complicated, dont understand.
@wfl-junior
@wfl-junior Жыл бұрын
8:53, don't need to exit fullscreen, you can scroll down in fullscreen mode :)
@jaysistar2711
@jaysistar2711 Жыл бұрын
This happens mainly because TypeScript drops its symbols into the parent namespace (or object) as well as having it's own, and also it doesn't have a concept of a type scope resolution operator that's different than the instance scope resolution. There also shouldn't be an enum that uses strings. The whole point of enums in C, C++, C#, and D is to create symbols rather than strings. (See SCHEME symbols vs. strings) The enums in Haxe, OCaml, and Rust are MUCH better, and interestingly, they are actually represented with a linear memory layout in Rust due to the availibilty of value types for more than primatives.
@charltonphan
@charltonphan Жыл бұрын
wow we were using enums as constants for some form field naming and it was super annoying to try and pass in values we know were suppose to work at runtime but enums were not happy about that (like just passing in the raw string) thank you matt!
@tntg5
@tntg5 Жыл бұрын
I use enums alot, and always with the string version. Never had a problem. If you don't assign strings to each enum property, then it defeats the purpose, because then you need to know by heart which index refers to which input
@EverydayJavaScript
@EverydayJavaScript Жыл бұрын
Amazing video Matt... Thanks...
@YuskaWu
@YuskaWu Жыл бұрын
In my opinion, it depends on the readability of value. enum give readability for unreadable value, using enum is better for those unreadable cases. But if value is readable, then you can just use the value as the type guard so that you don't have to import enum every time when you need it, especially there are many places using them, in that case using "const assertion" is much better for me.
@iAmTheWagon
@iAmTheWagon Жыл бұрын
The dad joke at 2:38 made me immediately like and subscribe :)
@DisturbedNeo
@DisturbedNeo Жыл бұрын
I would do: const LogLevel = { DEBUG: 'DEBUG', WARNING: 'WARNING', ERROR: 'ERROR', } as const; type LogLevel = typeof LogLevel[keyof typeof LogLevel]; Which allows you to use LogLevel.DEBUG as well as 'DEBUG', but all other values result in a compiler error, just like an enum.
@scaredphoenix945
@scaredphoenix945 Жыл бұрын
You can even make it immutable and no need to do 'as const' casting: export const StatusResponse = Object.freeze({ Ok: 0, PartiallyFailed: 1, Failed: 2 }); And do a type alias: export type StatusResponse = typeof StatusResponse[keyof typeof StatusResponse];
@MorgurEdits
@MorgurEdits Жыл бұрын
The first example is actually exactly how I expect Enums to work, there is the ordinal value of the Enum and then there is the value you assign for the Enum itself.
@JosephDalrymple
@JosephDalrymple 8 ай бұрын
I feel like this could be solved by disabling enumerability on the reverse map keys of the enum. At that point, you could still reverse lookup, but you could also still iterate through the keys.
@notthere83
@notthere83 Жыл бұрын
7:20 Huh? You can just assign string values in the enum and simply write "level" instead of "titlesMap[level]"? It's really strange to me whenever things in engineering change for the worse just because people don't understand the tools they use. I.e. rather than educate people, everybody declares the thing that is actually better than the alternative as bad. In this case, there's a reason why it has long been discouraged to use magic values throughout a code base. Using enums is a way of enforcing this. And yet... there's not just this video but even Ryan Cavanaugh recommends using string literals! 🤯
@arber10
@arber10 Жыл бұрын
Didn‘t even need to remove the fullscreen to press 👍🏻. Thanks!
@vintprox
@vintprox Жыл бұрын
Loving IIFE joke))) Although took your explanation to even catch that.
@ThaRealIansanity
@ThaRealIansanity Жыл бұрын
3rd time in a week revisiting this video. I turned the two type definitions into a one liner. Not sure if there is an issue with it but at first glance it seems to work fine for me. " type LogLevel = typeof SIZE[keyof typeof SIZE];"
@jalub014
@jalub014 Жыл бұрын
I find myself using enums quite a lot. The main reason I use them over something like union types is that our codebase isn't 100% in typescript - we are still using Vue 2 and we don't use typescript in the components - so using enums helps me to avoid typos.
@dealloc
@dealloc Жыл бұрын
You don't use an IDE that auto completes? Use it! Unions would also tell you when you made a typo anyway. Use the TS type checker in your JS files (add @ts-check comment at the top of your files), and you will avoid a ton of problems from typos. Typos shouldn't be the factor that introduces bugs in your code. This is one of the reasons to use TypeScript in the first place.
@jalub014
@jalub014 Жыл бұрын
@@dealloc Guess that it would need more work than that since when I add the comment all the properties from mixins error out.
@alcar32sharif
@alcar32sharif Жыл бұрын
Enums in TypeScript behave exactly as I expected as a Java, Python, C#, and C++ software engineer.
@McWolke92
@McWolke92 Жыл бұрын
enums are one of the best things about typescript.
@quantum_dongle
@quantum_dongle Жыл бұрын
I think there is a distinction that needs to be made for using explicitly assigned enum values. The default behavior of enums, and the 'as const' behavior is a little odd, but using them as a glorified string map forces users of the code to be explicit about where the values they are using are coming from, rather than passing a string literal into a function.
@ransomecode
@ransomecode Жыл бұрын
There are symbols in JS, which could be used as unique values: ``` const LogLevel = { ERORR: Symbol("error"), INFO: Symbol("info"), WARNING: Symbol("warning") } ``` see JS had enums all along😅
@EmNudge
@EmNudge Жыл бұрын
The unfortunate bit of using this with TS is that it won't enforce that specific symbol, even if you do `as const`. It will be fine if we call the function with `func(Symbol())` unfortunately.
@ransomecode
@ransomecode Жыл бұрын
@@EmNudgeit can be used at runtime and it's not just a structural/type level stuff like many things in TS. You're right however though, the ergonomics of Symbols just aren't there in TS yet. But the thing is they can truly be used to implement enums like in other languages. For example: ``` LogLevel.ERROR === Symbol("error") ``` will always be false because Symbols are unique and this is how enums behave in most statically typed languages
@EmNudge
@EmNudge Жыл бұрын
@@ransomecode Yeah, I've used symbols in a couple of my codebases. It's unfortunately not a complete solution for TS just yet since it ends being even worse than an enum.
@dealloc
@dealloc Жыл бұрын
@@EmNudge Indeed. I tried to use symbols as well but they are just not unique in the type system, only in the runtime :/
@Luxcium
@Luxcium Жыл бұрын
I feel like if Enums add something to the JavaScript side from the TypeScript side and I never have been happy about it… I realized that without thinking about it just because I was having all my types and interfaces in one same folder and Enum kind of needed to be in that folder and outside of it at a same time
@savagersd5340
@savagersd5340 9 ай бұрын
I really like the details and the way you explain stuff. In my case the solution you propose at 6 min onwards i disagree completly. I use enums because i dont want to pass a string.
@YeloPartyHat
@YeloPartyHat 9 ай бұрын
Going through all your videos. I had no idea about those runtime qwerks!
@andybrice2711
@andybrice2711 Жыл бұрын
I wish TypeScript would implement a shorthand enum syntax like Swift: log('Hey', .DEBUG) Having to write LOG_LEVEL.DEBUG is superfluous when the developer and the compiler already know the type of that argument.
@neonbyte1337
@neonbyte1337 Жыл бұрын
3:15 it does work for regular numeric enums.
@nickdivona8769
@nickdivona8769 Жыл бұрын
You don't even need to remove full screen to like a video, you can just scroll down in full screen mode, on desktop at least :)
@codevincas
@codevincas Жыл бұрын
What about the case when enum value is used as a type: export type State = | { name: AuthState.Loading } | { name: AuthState.Error; message: string } Using string literal in `name` doesn't let me keep a single source of truth, but the alternative with `as const` seems to be `typeof AUTH_STATE.LOADING` which seems pretty convoluted. Could also extract the type, but it's also not pretty: type AuthStates = typeof AUTH_STATE export type AuthState = | { name: AuthStates['LOADING'] } | { name: AuthStates['ERROR'], message: string }
@quelchx
@quelchx Жыл бұрын
@6:22 I came across something like this (forget where) and I have used systems like that and it is very very useful.
@MrTheWeir
@MrTheWeir Жыл бұрын
This is advice I wish I'd had when I first started with Typescript. I initially used string enums, but after some experience and research found that as-const POJOs were much closer to what I wanted from the enum. Also, for what it's worth, I did laugh at your IIFE joke.
@marcomow
@marcomow Жыл бұрын
I can only imagine how much time and experience are needed to produce this knowledge, that I can easily access and absorb in 9 minutes flat. Thank you so much! Buying the course today
@bdidue6998
@bdidue6998 Жыл бұрын
Gotta read them docs buddy!
@RaZziaN1
@RaZziaN1 Жыл бұрын
bullshit, guy is creating problems when in reality there are none.
@cool_dude_like_really
@cool_dude_like_really Жыл бұрын
I was thinking on why a certain enum doesn't act well as a type for hours just today... const ... as const is a blessing 😅
@fyriss_
@fyriss_ Жыл бұрын
Thank you for this high quality content. It's great place for intermediate TS dev, who wants to master his skills.
@anarchoyeasty3908
@anarchoyeasty3908 Жыл бұрын
Its ok Matt, I liked your IIFE joke
@gh0stcloud499
@gh0stcloud499 Жыл бұрын
Yes I kind of wish there was a lint to enforce enum assignments (e.g DEBUG = ‘DEBUG’, actually now that I think about it there probably is a lint for this somewhere out there). I think enums are great for making your code more searchable.
@Disorrder
@Disorrder Жыл бұрын
Lol, what a bullshit! Don’t listen, guys, enums are great for typing. It’s ok to import them. This is the purpose of typing - to avoid “magic” values
Infer is easier than you think
13:38
Matt Pocock
Рет қаралды 92 М.
Generics: The most intimidating TypeScript feature
18:19
Matt Pocock
Рет қаралды 180 М.
What's in the clown's bag? #clown #angel #bunnypolice
00:19
超人夫妇
Рет қаралды 43 МЛН
Cool Parenting Gadget Against Mosquitos! 🦟👶 #gen
00:21
TheSoul Music Family
Рет қаралды 33 МЛН
Yay, My Dad Is a Vending Machine! 🛍️😆 #funny #prank #comedy
00:17
The TRUTH About TypeScript Enums
12:04
James Q Quick
Рет қаралды 7 М.
I Feel Bad For New Programmers
19:12
ThePrimeTime
Рет қаралды 492 М.
30 Programming Truths I know at 30 that I Wish I Knew at 20
17:41
Why use Type and not Interface in TypeScript
14:12
ByteGrad
Рет қаралды 212 М.
TypeScript - Enums: Обзор и когда не надо использовать
11:24
PurpleSchool | Anton Larichev
Рет қаралды 15 М.
as const: the most underrated TypeScript feature
5:38
Matt Pocock
Рет қаралды 122 М.
RUST Enums ARE Better
5:49
ThePrimeagen
Рет қаралды 144 М.
Dependency Injection | Prime Reacts
28:34
ThePrimeTime
Рет қаралды 345 М.
The Worst Programming Language Ever - Mark Rendle - NDC Oslo 2021
1:00:41
NDC Conferences
Рет қаралды 1,3 МЛН
Goodbye, useEffect - David Khourshid
29:59
BeJS
Рет қаралды 502 М.
What's in the clown's bag? #clown #angel #bunnypolice
00:19
超人夫妇
Рет қаралды 43 МЛН