Check out a free preview of the full Making TypeScript Stick course
The "Primitive Types Quiz" Lesson is part of the full, Making TypeScript Stick course featured in this preview video. Here's what you'd learn in this lesson:
Mike discusses questions from the introduction quiz regarding primitive types. The union of the two primitive types, string and number, results in a never, whereas the interface types String and Number do not.
Transcript from the "Primitive Types Quiz" Lesson
[00:00:00]
>> Okay, now, this, we're gonna get much more interesting here in the world of TypeScript and types. And I expect this'll be a larger discussion of sorts. So in this example, we're being asked to look at the types of first and second below, and the compile error messages.
[00:00:20]
And we're being asked what does this tell us about how string with a lowercase s and String with a capital S are different? So let's look at this code example carefully. So we have a variable declaration called first, and we have the lowercase string, and then and, and then number.
[00:00:41]
And then below that, we have second, and then we have a similar type, except we're using the capital letter versions of these. So you may have heard before you always want to use this lowercase version of string and number, and these these primitive types. And by the end of this discussion, I think you will believe even more that that is the best way to do things, because stuff gets weird if you use this variant.
[00:01:08]
So let's look at what happens here. And by the way, in these code examples, this is, to some extent, VS Code in your browser. So if you're following along on the website, you can hover over these symbols, and you can see the types right on tooltips, just as if it's your editor.
[00:01:27]
So the type of first is never. So who can tell me what never means in the world of TypeScript? What kinds of values will make this variable happy?
>> No values.
>> No values, right? So in terms of the set of things I could pass to first to make it happy, it is the empty set.
[00:01:51]
So we can see that the type of first is never, meaning there is no value that we could give to first that would make it type check properly. The only thing we could give it is a never. It's effectively, it's an impossibility. For example, you could end up with a never if you took a number, and you could say, well, if it's greater than or equal to zero, do this one thing.
[00:02:17]
And if it's less than zero, do this other thing. And then you follow it with one more else block, a number that's neither zero, nor greater than zero, nor less than zero. What is that number? What could that be? And the answer is there is no number, right?
[00:02:33]
That's a never. That's what we mean by an empty set. It's sort of we've crossed everything off of the list of what this could be. That's what that means. So that's the type of first. And you might expect, well, the way we've defined second, that type looks very similar.
[00:02:50]
I mean, it's just a capital letter. Maybe String with a capital letter is just sort of an alias for the lowercase string. But if we look at that, it turns out it's different. And by the way, if we think about why first is never, somebody give me an example of something that is both a string and a number.
[00:03:13]
It's hard to think about that, right? Somebody write that in the chat. Give me an example of something that's both a string and a number. It's really we're kind of at a loss. That's why we end up with never. But here, second seems to be looking for exactly that, something that's both.
[00:03:32]
It's some hybrid string and number thing, but at the same time, not never. And we can see that our error message is a little bit different here. You can see we're attempting to assign it to a string. And we're getting an error that's telling us wait a minute, it has to be both a string and a number.
[00:03:53]
And yeah, I'm okay with the string part, but what you gave me is not assignable to a number. You're missing the number aspect of what I need to be given. And finally, here's another thing that adds to the confusion. This line down here, if we use the string constructor, which, this should look kind of strange to you.
[00:04:17]
We don't typically create strings this way in JavaScript. We get yet another different error message. And here we're saying all right, String with a capital S is not assignable to String & Number. And up here, you can see we had a lowercase s. So it seems like it's being regarded as a different type of sorts.
[00:04:37]
And then this final line down here, now we get deeper information about how, look, it's not just that this lowercase string is not assignable to type number. Now, we're being told we're missing some properties, and we might recognize that these are properties that one might find on numbers, right?
[00:04:56]
toFixed, toFixed is what you would use to get the correct number of significant digits after a decimal point. If you're printing out dollars and cents, you might use toFixed. So seems like these are different. So in terms of what this might tell you about how you should build your mental model, we can see that when we use lowercase string and lowercase number, we end up with this never thing.
[00:05:31]
But when we use these uppercase versions of these types, we see that we don't get a never. We get what appears to be the combination of the two interfaces that contain the methods on string, the methods on number. So something is different here. And it has to kind of do with what is different about these two types about string versus interface string?
[00:05:59]
So building on this example, again, we have first and we have second. What we're gonna do is try to create this impossible thing, this impossible thing that's both a string and a number. So here you can see if we just try to create a new type called Foo that is both a string and a number, it's extending to other interfaces, we get error messages telling us that there is some kind of collision here.
[00:06:27]
toString, valueOf, there's something different about these in string and a number. And when we try to merge them together, something goes wrong. But we can kinda collaborate together by explicitly specifying these in this way. So we can create this thing called bar, that it extends both the string and number interfaces.
[00:06:53]
And we can even create a value of that type. So [LAUGH] I'm using the spread operator to get both everything that's on number, and everything that's on string. And then I have to explicitly do one little dirty cast here, so that I get a never type as the return of the value.
[00:07:14]
And here we go, we can actually complete an assignment. And this is our string and number hybrid, but you see it still doesn't make this first variable happy. So what this should tell you about the mental model you should form here is, number one, use the lowercase flavors of these types.
[00:07:37]
They are the sort of atomic lowest level things. You see, if we try to hover over string here, we don't really get a tooltip. It's one of the most fundamental building blocks of the type system here. Use these, they are fundamentally different than these, because these are the methods.
[00:07:57]
This is the interface that describes what can be done with the string. But their richness will also introduce some complexity, and you don't end up with the types that you might think that you would get. So it may seem like a benign little, like a best practice. We don't really understand why we do it one way versus the other, but this can result in some serious ramifications to your codebase if you use the wrong one.
[00:08:25]
So we can create this thing that's both a string and a number, but we have to do it in sort of a hacky way. And this is a good reason to stay away from the interfaces and stick to these, string and number.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops