Mutability 12 exercises
solution

Inference differences between let and const

The first step in fixing the error inside of buttonAttributes is to read the error message.


type ButtonAttributes = {
type: "button" | "submit" | "reset";
};
let type = "button";
const buttonAttributes: ButtonAttributes = {
type, // red squiggly line under type
};

Hovering

Loading solution

Transcript

00:00 Okay, the question at the heart of this exercise is why is this erroring in the first place? We're assigning button to the type. And so when we pass it into our button attributes, well, it's going to be the same. So why doesn't TypeScript, like, why is it erroring here? So we can look at this type here and we can see that it says type string is not

00:19 assignable to type button, submit or reset. Hmm. If we hover over type, you can see that it's being inferred as type string. Why on earth would that be right? Because what we're doing here is we're saying this is a button. Why doesn't it just infer as type button, the literal button?

00:37 Well, this is because let can be mutated. We can further down the line or elsewhere in our code say type equals something else and it won't complain. We can, of course, do something funky here. We can give type an explicit type and say it can either be a button or submit or

00:57 reset, and then everything's fine, right? It doesn't matter, actually, that the type can be mutated. It's more that when you use let by default, TypeScript infers it as the widest possible version of that type because it can be changed and mutated. But what if we use const instead?

01:15 Const now says const type equals button and it gets inferred as that specific type. That's because if we try to change it later, type equals something strange. It would say you cannot assign to type because it is a constant and this would throw a runtime error, too. So TypeScript is actually copying the behaviour of JavaScript in this case.

01:36 And it's saying, OK, if you declare this as a const, I understand that this is supposed to be of type the literal type that you specify. And this means, too, that if you specify something else in there, it specifies the literal in there, too. So type could be true and then it would do that, too. This is a really interesting behaviour,

01:54 and it touches on the idea that TypeScript pays attention to mutability a lot when we're kind of talking about like types and inference. And we're going to see that a lot, that TypeScript copies the behaviour of JavaScript when it infers literals in your code.