This course has been updated! We now recommend you take the TypeScript Fundamentals, v3 course.
Transcript from the "Function Signature Overloading" Lesson
>> Mike North: This part is particularly interesting, overload signatures. So we have a function here called contactPeople. And I take in an argument called method and the type of method here is either the string email or the string phone. And then any other parameter that follows can be either HasEmail or HasPhone.
[00:00:27] The same types that we were using in the last exercise. So down here, let's make sure that this works as we'd expect. If I wanna contact people by email, I can do this, and that's invalid email address. But from a type perspective, it should work, this also works.
[00:00:49] This should not work, right, email, I mean, conceptually, this makes no sense. If I'm trying to email someone and they only have a phone number, we're gonna run into a problem. And unfortunately, this currently works. And the reason is we have defined two independent and unrelated constraints here.
[00:01:13] It can be either email or phone, the string, and then the objects that we take can be sort of a mixed bag of contacts with emails and phone numbers. So although these are the narrowest types we could provide for these two arguments in order to get done what we need to get done.
[00:01:32] There is some disallowed combination that we want to prevent. And TypeScript provides a way of doing this. So I wanna look at a tool tip here, contactPeople, and this matches exactly what we're seeing above, right? The first argument is one of our two special strings. And then this is our mixed bag of HasEmail and HasPhoneNumber.
[00:01:55] What I wanna do is create two additional function signatures, sorry for that little jump there. And these are specific valid ways to access this function. So the first one, you can only pass an email, and then you must give me a list of people with email addresses. Second one, only phone, and then, only HasPhoneNumber.
[00:02:22] If we look at our tool tip now, see that little 1 of 2 and 2 of 2? There are two specific ways that we can invoke this function, either specify the string email and give me objects with an email address. Or let's get a line with the string phone and HasPhoneNumber.
[00:02:42] And if we look at our third and problematic example here, it's telling us that we've provided an object with the phone number. So this either I have to change one thing or the other, right? It's currently erroring by saying, you gotta make this string phone, you're operating on people's phone numbers.
[00:03:02] I don't have email addresses, so,
>> Mike North: Note that we have two ways to access this function. And those are the specific function signatures we've defined up here. This is not callable from the outside. It just needs to be wide enough, general enough to accommodate all of the function signatures.
[00:03:26] So if I were to remove this, we'd run into an error on the phone signature saying the underlying implementation does not accommodate passing phone as the first parameter. So it just has to be general enough that it'll meet the needs of all signatures above it.
>> Mike North: Yes?
>> Speaker 2: So could you just safely remove the type signature from the actual function call?
>> Mike North: It depends what you mean by safely. So you could still, like from the outside world's perspective, it would be exactly as safe as it is right now. And I think what you're saying here is basically string,
>> Mike North: And make this an array of anys, right?
>> Speaker 2: Or even just removing everything, all the types from line 53 to 56.
[00:04:20] Cuz we've got the declarations on 49 and 50.
>> Mike North: Totally, and these would become what we call implicit anys. So this is gonna be an array of anys, this is gonna be an any. And from the outside world, because we can't actually access the signature, no type checking from the outside world ever is compared against this signature.
[00:04:39] So the outside world don't care, but within this function, I'm in the Wild West here. Within the function, I don't have any kind of type safety. So it's a good idea for the purpose of maintaining this function to not be super, super general. You might do something like this, especially if you end up creating a whole bunch of these signatures here.
[00:05:03] Like let's say, we had fax and SMS and smoke signal. And it starts to get to a point where this becomes a difficult to manage type. And I might fall back to string here, right?
>> Mike North: Good questions everybody.
>> Speaker 2: I have a quick question.
>> Mike North: Yes.
>> Speaker 3: So the overload signature's a documentation strategy?
>> Mike North: No, well-
>> Speaker 3: It seems kind of like one.
>> Mike North: It has documentation benefits, to be sure. Because it's very clear to consumers what they should be doing. But I only say it's not purely a documentation strategy because it actually has type checking ramifications. This signature on line 72, I mean, this attempt to invoke the function here, this is not type checking because we only allow a and a, b and b.
[00:06:05] And this signature here is trying to do a and b. It is like a disallowed range of arguments that we can pass in. So more than just providing useful tool tips, it is actually greenlighting certain styles of invocation and forbidding anything else that's not, that doesn't fit.
>> Mike North: Has anyone here ever worked with a language that supports pattern matching like Scala or Erlang or Elixir?
[00:06:40] So this is similar to patterns, where often you can define multiple signatures that are designed for specific cases. The difference here is you can only have multiple function heads. You can't have multiple implementations, right? But you can have multiple behaviors here, independent functions that share the same name and kind of stack on top of each other, just the signatures.