Check out a free preview of the full TypeScript 3 Fundamentals, v2 course:
The "Functions" Lesson is part of the full, TypeScript 3 Fundamentals, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Mike demonstrates how to create type annotations for the arguments and return values.

Get Unlimited Access Now

Transcript from the "Functions" Lesson

[00:00:00]
>> Mike North: The next thing we are gonna look at is functions, and function types. So look in the notes folder, this is the file that starts with the number 2, function basics
>> Mike North: So I have a function here called sendEmail and I have an argument her called to. And what I'm using here is HasEmail.

[00:00:38] And if I do, at least on a Mac, Cmd, click, that'll take me to this interface from the previous notes that we were going through. I exported this interface from the previous module, and you can jump to the definition of this type. So I'm gonna be reusing things as we go along, but this points out that we can import and export interfaces and types, just like we can do with values.

[00:01:09] This is how we indicate a return type, and it's actually the same convention we've been using for variables, It's colon followed by type. And this is an object that has two strings, recipient and body, and here we're just building up that body to send, apparently, some spam email.

[00:01:27] So this is a place where I tend to always use type annotations. And this is because I wanted to find the contract that this function has with other parts of my program. Type script can infer return types pretty well. But it's very easy to slip up and unintentionally change things, which I'll demonstrate in a couple of minutes.

[00:01:56] This is the arrow-function flavor of, basically, the same thing, and the only difference is you have the fat arrows. So it's the parameter list, colon, type, fat arrow implementation, right? Parameter list, colon, type, and then the fat arrow, and you'll get used to that. So, return types can be inferred.

[00:02:21] This is a function that will take a contact and, un terms of what this function needs, it may typically operate on things that have way more than just the property name. But I'm being conservative, in terms of allowing this operate on any object that has a property name.

[00:02:40] When I'm typing function arguments, I kinda wanna state the minimum thing I need, in order to avoid over-constraining the function, right? This might be useful elsewhere and I don't want to artificially impose additional requirements on what these arguments must be. I want it to be as flexible as possible.

[00:03:02] And what's happening here is, we split this string, contact.name, we split it by weight space. We throw, if there are less than two parts. And then we return an object where the first part is the first name, the last part is the last name. The middle name, if we only have two parts, ends up being undefined.

[00:03:23] Or we join everything in the middle together. So, if we look at the return type here, there it is. Oops, and we can see that it is correctly inferred, right? So the compiler's going through all possible paths of this program, and it's figuring out what all is possible to return here.

[00:03:45] If, instead of, so like, let's say we have this function, and, at some point, we need to handle the Madonna case or the Prince case, where it's just a mononym, there is no last name. So we would then go up here and say If parts.length = 1, instead of throwing, we can just return, oops, return { name: parts

[0] }.

[00:04:20] So now, we've added an additional possibility here where, now, we return an object, and typescripts try to impose some consistency here, but we've returned something that potentially has an undefined last name. In fact, all of these values will end up being undefined. So, I may not have intended this to work in such a way.

[00:04:47] And this may affect other parts of my code. So, I like to specifically state a return type, because it keeps me honest within all branches of this function, to make sure that what I'm returning is intentional. You know, sometimes you early terminate, right? If you determine that this function that was just called, it's no op now.

[00:05:09] And early terminating, what does that, if I just say return semicolon, what am I really returning there? If I invoke a function and it just says return, semicolon, what value do I get? Undefined. So, that will change what this function, it will change the type this function returns, and that sort of has a ripple effect through your code.

[00:05:36] And I would rather keep that boundary very deliberately created, and operate on both inside and the outside of the function, to make things work.
>> Mike North: So rest params work just like you'd just expect, nothing really interesting here. The only thing you gotta be aware of is the type of a rest param has to be array-like.

[00:06:03] Cuz it's gonna be consumed as an array.