Targeting a useRef Overload
Inside of the type definitions, there are multiple declarations for the useRef
hook that act like function overloads.
These are the different ways that useRef
can be called, and they will return a different thing based on what you pass it in.
In the first overload, you pass in an `initialValue
Transcript
0:00 Let's examine this. Let's dive into the types for useRef itself to see what's going on. There we go. Zoom out a little bit. One cool thing, you notice that there are multiple declarations for useRef. These act as function overloads. These are different ways that useRef can be called and it will return a different thing based on what you pass it in.
0:22 You can see here that we have an initial value. The firstOverload is it has useRef. You pass in the initial value and you get back a MutableRefObject with that thing in. If we were to do that, if we just say const mutableRef equals useRef, we'll pass it a string, and then we'll pass it also a string inside here. I'll just group these together so we can see them.
0:47 This mutableRef now, you see we're getting back React.MutableRefObject string. A cool tip here is that if you're using a certain overload, then you can command-click on the function and it will go to the exact overload that you're using. This one, we've triggered the firstOverload. Command-click that again just to show you. Command-click, firstOverload, very nice.
1:09 Over here, let's see which overload we're using here. Command-click there, and we're on the secondOverload. Interesting. Let's see if we can trigger the final overload. The final overload doesn't require any parameters at all. This overload is only triggered when you use an empty, when you don't pass anything to it.
1:29 Let's do that. Let's go thirdOverload. In fact, let me just group these properly. This is firstOverload. That's the secondOverload. This is the thirdOverload. The thirdOverload is when you don't pass anything. Let's command-click that and check. There we go. We're on the thirdOverload. Very cool.
1:52 Why am I pointing this out? If we look at the firstOverload and what it returns, then you'll see that we get a MutableRefObject. Let's just command-click there, take a look at this type MutableRefObject. This is just current T. You notice that it doesn't have readonly in front of it. In other words, this can be mutated.
2:14 Let's just check here. I do not want to save my changes that I did there. Let's check here. Let's go firstOverload.current equals blah, blah, blah. Absolutely fine. You notice on the secondOverload, if we try to do that, it's giving us an error. That's because secondOverload is a RefObject.
2:31 RefObject, if we take a look at it, is a readonly current or . This means then that what we're getting here is that we can't assign to it because it's readonly. Then the thirdOverload, just for completeness, we can see that this also returns a MutableRefObject with T or undefined.
2:55 Why does this one return a readonly ref? It's because if you pass in here, what they decided to do on the type level -- It's a strange decision but I do have to explain it because it makes sense but doesn't -- they decided that when you do use this thing here, you're saying to React, "I want you to manage this ref for me. I don't want to manage this ref."
3:25 If you were to pass in undefined instead, it won't work here because you have to pass in an initial value here. If you choose to either pass in, let's say, this or you don't pass in anything at all, then you hit the thirdOverload or the firstOverload. If you pass in , then you hit the magical secondOverload and you end up with a readonly ref where you intended it to be mutable.
3:55 This is just something you've got to learn until they get rid of this behavior, hopefully, in React 19. The thing you've got to learn is to look at these two cases where you either pass in this string up here or pass in the initial value or don't pass in the initial value or you pass in . If you pass in , you're saying to React, "I want you to manage this state for me or manage this ref for me."
4:23 There we go, a primer on ref on why it's weird. I hope that someday I can delete this video and you can delete this knowledge from out of your brains because this will have gone away. It's certainly one of the most annoying things about React and TypeScript working together.