React.js TypeScript Conditional Props - Props that depend on other Props

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Cool thank you, didnt know these tricks!

👍︎︎ 7 👤︎︎ u/davidfavorite 📅︎︎ Apr 01 2021 🗫︎ replies

Awesome to see things I didnt even dream were possible with Typescript

👍︎︎ 19 👤︎︎ u/X-FrEaK 📅︎︎ Apr 01 2021 🗫︎ replies

This is what I looking for so far! Thank you!

👍︎︎ 5 👤︎︎ u/hxxngvx 📅︎︎ Apr 01 2021 🗫︎ replies

This is awesome. Super simple extension of commonly used concepts in TS. Great explanation as well.

👍︎︎ 5 👤︎︎ u/BenignLarency 📅︎︎ Apr 01 2021 🗫︎ replies

April fools?

👍︎︎ 11 👤︎︎ u/Mallanaga 📅︎︎ Apr 01 2021 🗫︎ replies

Is this also how other libraries/frameworks solve this? Such as Next.js etc.

👍︎︎ 7 👤︎︎ u/KremBanan 📅︎︎ Apr 01 2021 🗫︎ replies

Very difficult when one of the conditional types is actually undefined

👍︎︎ 2 👤︎︎ u/bozdoz 📅︎︎ Apr 01 2021 🗫︎ replies

This is great stuff man! I use this quite often for the basic components in projects. Tuples is cool too!

👍︎︎ 2 👤︎︎ u/evonhell 📅︎︎ Apr 01 2021 🗫︎ replies

What a great video! Thank you!

👍︎︎ 2 👤︎︎ u/archcorsair 📅︎︎ Apr 01 2021 🗫︎ replies
Captions
hello youtube today we are going to talk about conditional properties using react with typescript if you are asking yourself what is a conditional property let me give you these four examples the first one let's say that we have a component with a property called square and if we have a square then the mandatory property is a width now let's say that instead of having a square we now have for example a rectangle if we have a rectangle you will see that this component is already failing if we scroll a bit we can see that we need a property called height because a rectangle is width and height so let's say that now we have width and height now it compiles we don't need to go to run time in order to get this error now let's say that instead of having a rectangle now we have a circle if we have a circle it doesn't have a property called width it will also not have a property called height and we will have a property called radius of the circle so this is usually what a conditional property is whatever value this shape has is having an impact on the other properties that we might receive in that component you can have other types of conditional properties let me give you another example as this component is called one or the other let's say that we have two properties one called collapsed and another one called expanded if collapsed exist we can't have expanded and vice versa is also true if we have expanded we can't have collapsed as you can see we have already a typescript error if i remove one of them the error goes away if i remove now expanded that arrow also goes away you can go a bit deeper on these like we will be on this panel let's say in order to be default collapsed we need to have a collapsed property if we don't have the collapse property we will already have an error in typescript we can still have just a collapsible panel without having the default collapsed now the hardest example and the one that we can get more benefit out of is this drop down which will be the fourth example we will be talking today let's say that you have a drop down and when you have a drop down you will use the select with options inside and you have a value and a label if we have just an array of strings or numbers that's very easy we grab whatever we have put that to the value and the same thing to the label but what if we receive for example an array of objects like this id one and the name as bruno another one as for example id2 and the name as juan which is my brother right now we need a way to get the properties in order to have the value and want to have the label so let's say that we have autocomplete over here to have a label prop and now if i do control space you can already see that i only have two options id and name if i don't put name let's say i put nam typescript is already complaining to me saying that nim is not assignable to the type id or name so typescript is giving us a lot of feedback about our api which is very very nice now i will put name i will just do an enter to be in the next line if i do now control space i have the value prop and i will have the same type of helpers in this value prop so if for whatever reason i'm trying to just pass strings once again and i keep those value props you can see that for the type string and number so i can also have numbers over here right for the type strings and numbers this value prop is not possible to be there because it doesn't make sense we will use the full string or the full number for the value and for the label so this will be probably the hardest example we will we will be doing today so i hope you enjoyed this video and let's jump into the real examples in order for us to implement the first example i will go a little bit slower than usual and the reason is because i'm assuming you are very familiar with interfaces in typescript but not that familiar with types so we will implement everything using interfaces and then we will slowly move into types because they will be helpful for our example number two up to number four okay so if you are an interface person you will probably initially create an interface similar to this one where we have drawer props and then we have a shape that can be a square or a rectangle or a circle okay and then you will have the width the radius and the height as optional properties the problem with that approach is that we doing it like that we don't have any helpers from typescript i can come over here and now i can even say that the circle has a height of 55 and we know that the circle should only have a radius not a height or a width so this is not good enough the next attempt that you might have is to use this some union types that we have over there but now create an interface for the square an interface for the rectangle and an interface for the circle and then using these union types for our props so let's try to do that let's do an interface for the circle an interface for the square and an interface for the rectangle and now over here what we need to do is circle props or square props or oops ctrl v or rectangle props and if we do it that way we have all the benefits that we saw already in the demo we can have the height saying doesn't exist for the type circle so i can now come over here and the autocomplete will tell me already radius so this is very good i can come over here change from a circle to for example a rectangle i have an error in my radius i can now ask for autocomplete to vs code and i have a height and a width so if i say height equals to 55 and the width equals to 33 for example my component is not complaining at all so bruno why are you tempted to now move us into types we could solve everything with interfaces right yes we could the reason that i'm incentivizing you to just learn types is because in the next examples it will be very useful for us so i will help you move this now into types so you understand the and the reason behind types okay so let me say that you now need in your drawers to have all the time a full name for example like this full name equals to bruno and if you are using interfaces you have usually two options or you come to every single one and you will put full name over here full name over there and full name over there and it will work but imagine that we need 10 properties like that well in that case probably you will create an interface called the full name and we will put full name over here and you will just extend the circle to have a full name the square extends to have the full name and the rectangle x tends to have a full name but that's also not perfect right because it's a lot of codes for probably not much benefit so how can we achieve that in the same way on top of that we want to export this type we have over here so we can already start by that to have drawer props and we can already export this type if someone wants to use this type elsewhere right now in order to have the full name using our types with intersections we can do the following full name oops full name string and now we will use an intersection right and just don't forget this parenthesis otherwise it will do something that's not what you expect right so let's put the parenthesis we can format the code and you might be asking yeah bruno but what is that commercial i doing over there what is that well that is literally doing the following you have this type which is full name and now we are merging that type with whatever comes after right in this case whatever comes after are our three interfaces right so you can come over here and now full name is a valid property of our rectangle it's a valid property of our square so i don't need this height it's a property of our square and also from our circle i can now have autocomplete for our circle and i can come and say radius equals to 44 right now this is doing exactly what you want but keep in mind that you will see the change i'm going to do quite often for people that are used to types so instead of having the interface is declared like we have over here a lot of people will do the folding they will copy this bit well not copy they will go it directly right and you will have they will have a shape for radius right they will do the same thing for the square and let me just remove the new lines from there right and then the same exact thing for the rectangle so you will end up with something that for people that are transitioning from interfaces can be a bit harder to understand at least it was for me right i don't know if you will have the same problem as me or not but when i saw this type of code the first time it was a bit scary okay so if it is scary to you don't worry too much it's normal i will say okay so now you can see that we have the full name we have this intersection we have the parenthesis that end over there and now inside those we have a circle that has a radius we have a shape of square that has a width and another one which is the rectangle and we have a width for the number and the height that is another number so this first example is working and some of you might be asking how typescript can understand if i say circle that i have a radius only property and not the others well the way that typescript is doing that is because we have this shape property in all of our unions okay so when we are creating this union type it's easy for typescript to understand that if we have a shape of square the only possible other property is the wheat okay now when we go to the second example you will see that's a little bit different for our second example as the name implies we want to have one property or the other in this case let's say that we want to have a panel with expanded or collapsed it doesn't make sense for a panel to receive both collapsed and expanded at the same time so let's say we want to avoid having both at the same time the first write that you might do it will be something on those lines collapsed and you will say that it will be a boolean and then you say expanded which will be also a boolean but if we do that we can still set both at the same time as you can see i can come over here and say expanded i can say collapsed and i don't have any typescript error if i delete just one it still works if i delete everything it still works so what can we do in order to for example when i have a collapse to be boolean to not have an expanded to be boolean well this is a keyword that exists in typescript called never and as the name implies if we have a type to be never we can never set collapsed with expanded so if i now do collapsed and then i try to do expanded you will see that expanded is not in that type so we get that error now in order to do the opposite we can use the union types again so we will say or we copy this and we just change where the boolean is to where the never is and now we put never over there so now we have an error from typescript we can argue if these errors from typescript are good enough or not that's a different discussion but at least it's already complaining at compile time i don't need to run my application to see the error as a developer that's very good for our productivity right now if i just have one of those it works if i have the other it also works if i don't have any it also works now let's say that you don't want to have people doing the following collapsed equals to false for example we are allowing people to do that but if you don't want people to do that in your interface you can come over here and say the collapse instead of being boolean you only accept true so now this is already filing because it says typefalse is not assigned to the type true so if you want that now nobody in your interfaces can send the type equals to false if you want that that's how you do it okay now that we have this example done we can now jump into the third one for our third example let's say that we have once again a panel and this time our panel is always expanded and someone after two three months of development comes to us and asks hey can i pass another property called collapsible when i pass that property if someone clicks on the other i can collapse and extend the panel if i don't pass that property you shouldn't do anything to that panel without thinking too much we go and we implement that new collapsible collapsible property right so now we can come over here into the following panel and we can do collapsible and our panel is collapsible if we don't pass anything we have the normal panel another two three months pass by and as we know requirements are always changing and someone comes to us and says hey look i really now need another property if we pass the property collapsible we need another property to have a default collapsed so if we have those two properties it starts as collapsed then if the user clicks it expands and it's the same as before but i need to pass those two properties i need to pass collapsed and default collapsed if i don't pass the collapsed it shouldn't work for the default collapsed all right we have a new requirement is a bit weird but let's implement this requirement let's say that we have that collapsible and you will be tempted to do immediately something on those lines default collapsible collapsed sorry it will be a boolean right and this needs to be optional the problem is if we just do that now we can have the default collapse as we want but we can still do this and as you can see typescript is not complaining at all so what can we do in order to make typescript complain at us well you can say that this needs to be true and if i do now then and i remove this optional bit from there now you can see that it's complaining to me i can come over there and say once again collapsible and it works but we created another problem so the problem we created now is that i can't just have a normal panel because it will tell me that i need to have a collapsible property so what we can do in order to fix this issue is to come over here use once again our union i can even copy this to avoid any typos so let me just go to the next line paste that one and we can say the following if we don't type anything so never over the collapsed now we can say also never to our default collapsible right and now this bit works we can come over here i can say collapsible it works i can even have the autocomplete for the default collapsed if i remove the collapsed now i have an error and once again we can argue about the quality of the errors in typescript for this type of situations but this one is not too bad it says collapse collapsible is declared here and if you go one level above you can see property collapsible is missing in type default collapsed true but required in this specific type over here which is our type from here right so this is good in the end we can understand the errors right and that's also the reason i always say even though we have very good interfaces having nice documentation for developers to go and see it's very very important still right so just because you have very good properties and developers can still understand your api it doesn't mean you don't need to have proper documentation okay now with that being said we can still create these default collapsed we just need oops we just need to say collapsible and default collapsed now if you for whatever reason once again like before you don't don't want people to to do this to you you don't want people to say default collapsed equals to false you can come over here and force a true to be set right so now it will trigger an error to you i can delete this and if i do this it works if you want to allow that you can just say boolean and now you allow that it's up to you which one you prefer i will do the commit as is but i can leave a commented line over here if you just want to have that one okay so now that we have these bases we can now jump into the fourth example which will be by far the most complicated of them all let's now start our fourth example for our drop down and this drop down can receive either an array of strings or an array of objects if we receive the array of objects we will need two extra properties one to tell us which one is the value inside this object and the other one to tell us which one will be used as label so let's start by the string array and then we will make it a little bit more complicated so in order to have our string array we need to have something like this an array of strings and then we will say the label property will never be defined over here we will do the same for the value property and now that we are accepting an array of strings we can also accept an array of numbers right so i think it makes sense in a drop down if we want to send numbers it can be either the value and the label as the number right so let's now come over here and let's say the following drop down and our drop down can now accept data equals to an array of one two three so this is good and we can pass a string over here if i try to pass the label prop for example it will now file saying we shouldn't have that over there so this is a good starting point then you will need to have an array of objects for our data so you will be tempted to do something on these lines this will not be enough but let's start by this object not object sorry array of object and now we will have a label prop which will be a string and we will have a value prop which will also be a string let me just put a comma there and now this is already starting to fail i can come over here and say for example i receive a which is 5 b which is 6 and c which is 7 for example right so if i now come into the label prop i can say a and i can say that the value prop is for example b right so typescript is not complaining at us at this stage what can we do now more in order to have autocomplete because i would love to have ctrl space and f a b and c over here to autocomplete how can we do that well in order to do that we will have to have generics over here so if you never use generics you will see that's not that complicated what we are going to do is the following i will have a generic over here and i will say that my array it will be of whatever that type that we are receiving okay and you will see in most places t but you can call this whatever you want right if you want to call it asd isd this is a generic as well and you can use that okay so i will even leave this for a while as i st and before we finish i will put it back as a t normally right so now that this drop down props is with generics i will have to pass the generics up the chain over here and i will just do over here right so now what we need to do in order for this label prop to be a property of this object well typescript already has something called key off and in this case it will be key of asd isd right so i will do that key of that thing and now if i do autocomplete i have already a b and c i can do b over here if i put for example d now it fails and the failure is with a really good message it says type d is not assignable to the type a b and c so that's very good from typescript let me put this back st because it's i think a little bit easier to read okay d and t once again but now you know that you can put any variable variable name that you want over there right not variable but any name that you want over there for that type now let me just show you that we solved this bit but we created another bug can you guess what is the bug stop the video and try to guess what the bug is and i will tell you now so if we now do for example a and b now this is in reality going over here and you can see that i have all the methods from the string i can do for example two lowercase and in this one i can say two uppercase and i even have autocomplete as you can see right so this is not what we want right this is absolutely against everything that we wanted in the beginning so what can we do in order to avoid this type of problem well we can change what we have over here just a slight bit and we will fix the problem so we can say the following t extends number or string so we are asking if our type that we are receiving so whatever we are receiving here so this a is this b in this case if they are a number or a string if they are and this is just a normal ternary now right if you are used to ternaries in typescript or javascript this is just a normal ternary so i will just remove this and put the column and so what we are saying is if our type is a number or a string please oops please use this bit over here okay otherwise use this bit over here and as you can see now i'm already having problems because it's already saying that the type string is not assignable to the type of undefined of these two so this is very good let's see if we didn't destroy what we did before so i will now pass two objects for example with id5 name bruno i will pass another object with id6 which is for example my brother right and now this is filing which is very good because i need to pass those two properties if you scroll on the errors you will see that basically this type is missing the following properties from and the properties are those two which is very good in terms of understanding the api of the component we are using right now let me just say label prop equals to id your name in my case i want the id for the or the opposite i want the name for the label property and for the value property i will have the id and probably now my face is in front of the code so let me format this and now you have this over here right we have the best of both worlds we can have a string so if i put back i will put back a string but i will commit as is right now okay so i will put back a string i can do isd isd for example and these properties now shouldn't be used which is very nice i can delete them and i have the best of both worlds our users if we use something like this will not need to go to the documentation as much as normal because they already know that these label properties can only be the id or the name and this type of trick you can use in a lot of places in typescript you can use that key off to just have an object and everything that you are going to receive it will be a key off of that object so if you have any questions or anything that you might ask me as always the comments are open for you to ask questions and i will answer them all so i really really hope that you like this one if you did like the video subscribe to the channel and i hope you want to see one of those videos over there on my right and my left so see you next week bye
Info
Channel: Bruno Antunes
Views: 12,138
Rating: undefined out of 5
Keywords: react, react typescript conditional props, react conditional props, react typescript props that depend on another props, typescript props that depend on other, react typescript, react.js typescript, react js typescript, prop that should only be set when another prop has a specified value, react typescript conditional properties
Id: vXh4PFwZFGI
Channel Id: undefined
Length: 26min 14sec (1574 seconds)
Published: Tue Mar 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.