1 00:00:00,168 --> 00:00:01,232 Welcome back. 2 00:00:01,232 --> 00:00:02,544 In the last video, 3 00:00:02,544 --> 00:00:07,961 we learned about the basics of generics by creating our very own from scratch. 4 00:00:07,961 --> 00:00:12,141 In this video, we're going to learn about union and 5 00:00:12,141 --> 00:00:15,086 intersection types in TypeScript. 6 00:00:15,086 --> 00:00:20,921 If you're following along with the project-files that come with this course, 7 00:00:20,921 --> 00:00:25,921 we'll be working from the unions-intersections-begin folder. 8 00:00:25,921 --> 00:00:27,860 Let me show you where that is. 9 00:00:27,860 --> 00:00:30,974 I'm going to open the file explorer on the left hand side. 10 00:00:30,974 --> 00:00:39,004 And you can see that it's inside the manipulating-types folder and down here. 11 00:00:39,004 --> 00:00:42,994 As usual, that is a similar file with -end, 12 00:00:42,994 --> 00:00:48,151 which will contain the code we'll have after this video. 13 00:00:48,151 --> 00:00:52,855 If you ever get stuck or just want to see what we'll end up writing, go ahead and 14 00:00:52,855 --> 00:00:54,798 have a look inside that folder. 15 00:00:54,798 --> 00:01:02,230 For now, we're going to create a new file in the unions-intersections-begin 16 00:01:02,230 --> 00:01:06,500 folder called unions-intersections.ts. 17 00:01:09,687 --> 00:01:16,438 So union and intersection types are very simple despite sounding a bit complex. 18 00:01:16,438 --> 00:01:20,848 Let's imagine we're getting some data from an external source, 19 00:01:20,848 --> 00:01:24,953 and we're not exactly sure what the type of that data will be. 20 00:01:24,953 --> 00:01:28,972 But we know it can either be a string or a number. 21 00:01:28,972 --> 00:01:33,506 It can't be anything else other than those two types. 22 00:01:33,506 --> 00:01:37,022 That's where unions become really useful. 23 00:01:37,022 --> 00:01:41,577 Let's create a variable called id. 24 00:01:41,577 --> 00:01:48,806 And we'll give this a type of string | number. 25 00:01:48,806 --> 00:01:54,823 What we've done just here on line 1 is created our first union type. 26 00:01:54,823 --> 00:02:01,910 This tells TypeScript that our id variable can either be a string or a number. 27 00:02:01,910 --> 00:02:04,595 Let's test it to see if this works. 28 00:02:04,595 --> 00:02:08,108 First, we'll assign id to a number. 29 00:02:08,108 --> 00:02:11,942 And we'll see, we get no errors from TypeScript. 30 00:02:11,942 --> 00:02:15,002 Let's try assigning it to a string. 31 00:02:15,002 --> 00:02:18,819 And again, we get no errors from TypeScript. 32 00:02:18,819 --> 00:02:22,251 And this is pretty much all there is to union types. 33 00:02:22,251 --> 00:02:26,094 You can unite as many types as you want. 34 00:02:26,094 --> 00:02:28,016 Let's try another example. 35 00:02:28,016 --> 00:02:30,743 Let's create a variable called canDrive. 36 00:02:34,015 --> 00:02:39,891 We'll give this a union type of string, number, and boolean. 37 00:02:43,923 --> 00:02:47,244 Cool, and you can imagine what we can do with this variable. 38 00:02:47,244 --> 00:02:53,048 We can give it a value of a string, like yes. 39 00:02:53,048 --> 00:02:56,712 We can also give it a value of a number, like 0. 40 00:02:56,712 --> 00:03:00,193 And we can give it a value of a boolean, like true. 41 00:03:00,193 --> 00:03:04,429 And TypeScript is happy with any of these values. 42 00:03:04,429 --> 00:03:09,719 Of course, if we give it a value outside of the types that we've given 43 00:03:09,719 --> 00:03:14,755 in our union, like dates, then we get an error from TypeScript. 44 00:03:17,052 --> 00:03:20,958 You can even create type aliases for unions. 45 00:03:20,958 --> 00:03:24,467 We can do that above our variable on line 6. 46 00:03:24,467 --> 00:03:26,748 Let's correct a type alias called CanDrive. 47 00:03:31,126 --> 00:03:35,457 And let's copy the type from line 7, and paste it into our alias. 48 00:03:35,457 --> 00:03:40,680 Now, we can replace the type on line 7 with our CanDrive type alias, 49 00:03:40,680 --> 00:03:42,947 and everything still works. 50 00:03:42,947 --> 00:03:46,154 You can even create a union array. 51 00:03:46,154 --> 00:03:49,764 Let's make a new variable called ids. 52 00:03:52,040 --> 00:03:57,098 This will have a union type of string and number, but 53 00:03:57,098 --> 00:04:00,717 there will be an array of this union type. 54 00:04:00,717 --> 00:04:06,129 You probably think we can do that by adding square brackets after the number. 55 00:04:06,129 --> 00:04:11,865 But that won't work because that will mean a union type of string and number array. 56 00:04:11,865 --> 00:04:16,789 So to get around that, we can put round brackets 57 00:04:16,789 --> 00:04:20,712 around number and string, like so. 58 00:04:20,712 --> 00:04:25,105 And now what this does is allows us to create an array that 59 00:04:25,105 --> 00:04:28,760 can either have a number or a string inside it. 60 00:04:28,760 --> 00:04:29,702 Let's test that. 61 00:04:31,707 --> 00:04:36,911 I'm going to assign a mixture of strings and numbers to this array. 62 00:04:36,911 --> 00:04:42,948 And we can see, we don't get any errors from TypeScript. 63 00:04:42,948 --> 00:04:45,584 Now, you might be thinking, 64 00:04:45,584 --> 00:04:50,864 why would I use a union type array over a tuple or vice versa? 65 00:04:50,864 --> 00:04:53,924 Well, the difference between a tuple and 66 00:04:53,924 --> 00:04:58,735 something like this union type annotation we've written on line 67 00:04:58,735 --> 00:05:03,468 13 is simply the fact that a tuple has a fixed number of values. 68 00:05:03,468 --> 00:05:08,579 And you can determine the type of each value in the array based on its position. 69 00:05:08,579 --> 00:05:11,994 So the first value could be a string, second could be a number, 70 00:05:11,994 --> 00:05:15,742 the third could be a string, and you have those set number of values. 71 00:05:15,742 --> 00:05:22,740 Whereas in an array, you can't specify the type of a value in a certain position. 72 00:05:22,740 --> 00:05:28,375 So I can't say that the third value in this array has to be a string. 73 00:05:28,375 --> 00:05:33,222 Okay, we'll come back to unions at the end of this video. 74 00:05:33,222 --> 00:05:36,897 But for now, let's jump to intersection types. 75 00:05:36,897 --> 00:05:41,212 Intersection types allow us to combine multiple types into one. 76 00:05:41,212 --> 00:05:43,376 Let me show you with an example. 77 00:05:43,376 --> 00:05:46,400 Let's create a new type alias called TeamLead. 78 00:05:49,063 --> 00:05:55,927 A TeamLead in our case is someone who has a job but also manages people. 79 00:05:55,927 --> 00:06:02,203 For this type alias, we'll be using some types that we wrote in our previous video. 80 00:06:02,203 --> 00:06:07,574 If you haven't watched that video, don't worry, you can go ahead and 81 00:06:07,574 --> 00:06:11,975 download the project-files that come with this course. 82 00:06:11,975 --> 00:06:15,601 We can navigate to the generics folder, and 83 00:06:15,601 --> 00:06:21,682 there should be a file in the generics-end folder called generics.ts. 84 00:06:21,682 --> 00:06:26,578 We can grab the first two type aliases from that file and 85 00:06:26,578 --> 00:06:32,125 paste it inside our unions and intersection files, like so. 86 00:06:32,125 --> 00:06:37,257 You may also need to grab the person type alias from the generics file 87 00:06:37,257 --> 00:06:42,585 as it's being used in the manages property of the Manager type alias. 88 00:06:42,585 --> 00:06:49,046 As I already have those type aliases, I get an error, so I'm going to remove it. 89 00:06:49,046 --> 00:06:53,695 But if you don't have them, you shouldn't get this error. 90 00:06:53,695 --> 00:06:56,353 Okay, back to our TeamLead type alias, 91 00:06:56,353 --> 00:07:05,066 we are going to give this a value of Employee & Manager. 92 00:07:05,066 --> 00:07:10,915 What this has just done is combine our two type aliases together. 93 00:07:10,915 --> 00:07:16,733 So if you were to create a variable that matches this TeamLead type, 94 00:07:16,733 --> 00:07:23,694 it will need to contain everything in Employee as well as everything in Manager. 95 00:07:23,694 --> 00:07:25,449 Let's check if that worked. 96 00:07:25,449 --> 00:07:29,901 We're going to create a new constant variable called jim, 97 00:07:29,901 --> 00:07:33,472 who will have the type annotation of TeamLead. 98 00:07:33,472 --> 00:07:38,553 This will be an object that will contain the name property, which will be Jim. 99 00:07:41,192 --> 00:07:46,710 The job property, which will be Lead, 100 00:07:46,710 --> 00:07:50,557 and the manages property, 101 00:07:50,557 --> 00:07:57,092 which should contain an array of tim and jack. 102 00:07:57,092 --> 00:08:01,695 Again, the tim and jack variables are inside 103 00:08:01,695 --> 00:08:07,040 the generics file we created in our previous video. 104 00:08:07,040 --> 00:08:11,362 If you don't have that, don't worry, you can go ahead and 105 00:08:11,362 --> 00:08:16,386 grab those two variables from the file in the generics-end folder. 106 00:08:16,386 --> 00:08:22,166 They should be just below the type aliases we copied down here, so tim and jack. 107 00:08:22,166 --> 00:08:28,631 So let me explain what this type intersection has just done. 108 00:08:28,631 --> 00:08:33,737 So as we can see, Employee has a name and job property, 109 00:08:33,737 --> 00:08:37,964 and Manager has a name and manages property. 110 00:08:37,964 --> 00:08:43,576 Now, the intersection has been clever enough to notice that both Employee and 111 00:08:43,576 --> 00:08:46,724 Manager contain the same name property, so 112 00:08:46,724 --> 00:08:49,971 we don't have to write that property twice. 113 00:08:49,971 --> 00:08:55,705 But as noticed, that Manager does not have the job property, 114 00:08:55,705 --> 00:09:00,351 and Employee does not have the manages property. 115 00:09:00,351 --> 00:09:05,411 So when it combines these two type annotations, it grabs a name, 116 00:09:05,411 --> 00:09:10,656 it grabs job, and grabs manages, and puts it together in one type. 117 00:09:10,656 --> 00:09:14,838 That's why we need to add all those three 118 00:09:14,838 --> 00:09:20,007 properties inside our new variable on line 20. 119 00:09:20,007 --> 00:09:23,794 Notice for the intersection type example for 120 00:09:23,794 --> 00:09:29,083 TeamLead on line 18, I used type aliases I created earlier. 121 00:09:29,083 --> 00:09:34,090 I don't think the intersection type works well with primitive types because 122 00:09:34,090 --> 00:09:39,650 you can't really combine primitive types the same way you can combine object types. 123 00:09:39,650 --> 00:09:42,723 Let me show you with an example. 124 00:09:42,723 --> 00:09:46,545 Let's create a new type alias called StringNum. 125 00:09:48,368 --> 00:09:54,110 And this will be an intersection of string and number. 126 00:09:54,110 --> 00:09:58,337 If we hover over our StringNum type alias, you'll see it says, never. 127 00:09:58,337 --> 00:10:04,078 And that's because you can never combine a string and number together. 128 00:10:04,078 --> 00:10:09,428 These values are primitive, and therefore do not contain other values 129 00:10:09,428 --> 00:10:14,529 that can be merged together, like the Employee and Manager types. 130 00:10:14,529 --> 00:10:18,757 If we create a variable called test5, 131 00:10:18,757 --> 00:10:24,008 give it the StringNum type and give it a value of, 132 00:10:24,008 --> 00:10:28,875 say 20, you'll see we get an error because 133 00:10:28,875 --> 00:10:33,636 you can't assign number to a type of never. 134 00:10:33,636 --> 00:10:35,711 I hope that makes sense. 135 00:10:35,711 --> 00:10:39,527 Anyway, let's comment the last few lines we worked out. 136 00:10:39,527 --> 00:10:42,738 And let's go back to type unions. 137 00:10:42,738 --> 00:10:49,579 So let's create a constant variable called singleIds. 138 00:10:49,579 --> 00:10:54,015 We'll give this a value of ids that have been split. 139 00:10:54,015 --> 00:10:58,892 This works fine because the last id value we had was 12. 140 00:10:58,892 --> 00:11:02,778 And we can split that into 1 and 2. 141 00:11:02,778 --> 00:11:07,440 However, if we change our id to a value like 5, 142 00:11:10,586 --> 00:11:15,339 Then you can't really split that because the split method 143 00:11:15,339 --> 00:11:18,254 doesn't exist on a type of number. 144 00:11:18,254 --> 00:11:21,622 This is something that can totally catch you out. 145 00:11:21,622 --> 00:11:26,355 Because id is a union type of both string and number, 146 00:11:26,355 --> 00:11:31,100 TypeScript is happy for you to assign a number to id. 147 00:11:31,100 --> 00:11:35,616 But you can't use string specific methods on a number, and 148 00:11:35,616 --> 00:11:39,606 you can't use number specific methods on a string. 149 00:11:39,606 --> 00:11:43,728 How would we go about fixing an issue like this? 150 00:11:43,728 --> 00:11:48,760 Well, this is where something called type narrowing comes in. 151 00:11:48,760 --> 00:11:52,548 And we'll talk about that in a later part of this course. 152 00:11:52,548 --> 00:11:57,303 But in the next video, we'll take the complexity down a bit and 153 00:11:57,303 --> 00:12:03,600 talk about the difference between a type alias and something called an interface.