Transcript from the "Structural vs Nominal Typing" Lesson
>> First, let's talk a little bit about what type checking is. And type checking happens whenever we're trying to assign a value to a variable, when we're passing an argument to a function. A function returning a value, right, remember our number return type, and we were playing with undefined there.
[00:00:21] It's seeing what you're actually returning, how does that compare to what you've stated you'll return? So that's another place where TypeScript is asking the question of type equivalence, is type y equivalent to type x? And it's really, this question comes down to like, does the type of y fit within the type of x?
[00:00:45] So if you're returning a number from a function, if that's what you say you're going to return, and you return 43, always, for 43 fits within set of numbers, that's perfectly fine. But if you say you're going to return the number 43 and you return some other random number, that doesn't fit.
[00:01:04] It's really, if we think about our mental model of sets, it's a question of subsets. Is one type a subset of the other type? So, in this case, this is very similar to what we had in our add function, right? We flipped a coin, math that random, see if it's greater than 0.5, and we said we would return an array of strings, but we're returning undefined.
[00:01:35] We're returning a value of type undefined. And that is nowhere in the set of string arrays, the set of all possible string arrays that could exist, undefined is not in there. And so, we would say, well, our return value here, it is not type equivalent to string array.
[00:03:18] So other common programming languages are Java, C#, and C++, they all involve static types. Many other languages do as well, but these are really, really popular ones. And dynamic typed languages include Python, Ruby, Perl, and PHP, although, there are sorbet types for Ruby and I think, Python has TypeShed.
[00:03:44] There are ways to add some level of typing to these languages, but at their core, they are dynamically typed languages. Duck typing is very similar to dynamic typing, and we'll talk a little bit more about that in a second. So, you may see the term strong versus weak types, this really strong and it's not really a spectrum that makes sense for type systems.
[00:04:16] Although people treat the static types as strong because they're more explicit. They usually allow you to articulate more interesting things, but there is no consensus definition of what strong means or weak. But these terms are test around a lot. All right, this is kind of the interesting part.
[00:04:37] What is a nominal type system versus a structural one? So this is a piece of Java code. And you'll notice it's Java code because we've got like this public word before the class and public static string. So, we've got our car here with make, model, and year. And we've got another class here that is a car checker.
[00:05:01] And it checks a car and it returns a string. This is where you put the return type in Java. And we could create a car. And if we do CarChecker.checkcar, we don't see the implementation of this function. But if this were a type equivalence check, what Java's really gonna be asking is, are you an instance of the class called car?
[00:05:27] It doesn't matter what properties you have, you have to be an instance of a class named car. This class, that's what nominal means when we say a nominal type system. All that matters is your constructor. Where did you come from? Typescripts type system is structural. So here's an example of, we have a class car, we have a class truck, we have an object we've created, which has some inference, right?
[00:05:58] It's gotta make model in here, we've been dealing this all morning. And when we've got our printCar function, it's happy to take the car, the truck, the vehicle, all that matters is that we meet the requirements of what the argument wants. We don't have to have come from a particular constructor.
[00:06:20] We just have to have the same structure. We have to have the right properties, that's basically the right shape. It's not just properties, right? Cuz we could need a method to be present on the argument passed to us. So, I mean, it's still a property, it values function, but we could require that an index signature be present.
[00:07:35] I'm sure someone can create an example where it's impossible, but 99.9% So, here's an example, just going back to our set theory example, or sorry, let me not toss around like complicated terms like that. Thinking of types as representing a set of allowed values. If we think about the print car argument, here's the set.
[00:08:25] So because Car and Truck instances and cars set, if you looked at the type car, it's like all possible Car instances, all possible Truck instances. They're each subsets of this setup here, every single one of those instances will meet this condition. So let's go back to the big question of type equivalence, is y type equivalent to type x?
[00:08:51] It's really, does the type of y fit within the type of x? Or is the set represented by y? A subset of the set represented by x. Caitlin asks a good question here. What if the object has more properties? So I'll go back up to the example here.
[00:09:11] What if the object has more properties than are needed? Will it still work? It'll absolutely still work, here on truck we've got towing capacity on electric, sorry, on car we've got is electric. Those sort of paths straight through, the function is more than happy to work. This kind of relates a little bit to the access property checking, where we had that color red and remember that was like an inaccessible property and TypeScript was warning us about.
[00:09:39] But the function is perfectly happy to take anything that meets this condition. This set of allowed values, you could have like an object with a thousand properties that the function doesn't care about. But as long as it has make, model, and year of the right types, printCar is totally happy to receive that.
[00:10:02] So what this lets you do is, instead of having to have this big ontology of different objects, right, these modeling everything in your program as instances of a class, and you can just say, all right, here are the requirements I have. I'm building this print car function, maybe you start with this line and you're like, I wanna print this.
[00:10:23] What do I need to be true in order to safely print this? Well, I just need to have a variable, which has make model and year on it. Willis asks, what if you use constructor in the car or truck? would print car still work? I'm just gonna point out these two lines here, I think that's what you're asking.
[00:11:10] Instanceof might be what you're you're looking for. Like, if, Something like that without this extra if. This is how you would sort of determine whether something's an instance of date, but it's important to know what you're doing here. It's a little bit like nominal types, so if you think about it, you can define a nominal type system within a structural type system.
[00:11:51] Structural-type systems are, they include everything that you can do in nominal type systems. Like this, right, here we're not saying, does x include a specific set of properties on date. We're saying, did this come from the date constructor? So this is a very nominal-ish thing to do, but that's okay.
[00:12:08] Structural-type systems are about allowing that and a greater set of capabilities, such as the flexibility of just stating, give me a thing that has these fields on it, I don't care where it came from.