TypeScript Basics: Function Types
Welcome to the Function Types lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
We've seen function definitions with types. But what if we want to put a function in a variable? The variable will need a type that says "I hold a function."
A function type looks like
(n: number) => number. In English, "a function that takes a number and returns a number.">
function five(): number {return 5;}/* This is the type of the function itself. */type TakesNothingReturnsNumber = () => number;const myFive: TakesNothingReturnsNumber = five;myFive();Result:
5
Here's an
add1function, followed by two examples that apply different static types to it. (One of them will cause an error; you can writetype errorto indicate that kind of error.)>
function add1(n: number): number {return n + 1;}- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
type TakesNumberReturnsNumber = (n: number) => number;const myAdd1: TakesNumberReturnsNumber = add1;myAdd1(3);Result:
4
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
type TakesNumberReturnsString = (n: number) => string;const myAdd1: TakesNumberReturnsString = add1;myAdd1(3);Result:
type error: Type '(n: number) => number' is not assignable to type 'TakesNumberReturnsString'. Type 'number' is not assignable to type 'string'.
Look closely at the type error above. The function
add1was fine: its type is(n: number) => number. The problem occurred when we tried to assign that function to a variable of type(n: number) => stringThe second line of the type error explains exactly why the functions aren't compatible. It's because their return types are different. The function
add1returns anumberbutTakesNumberReturnsStringreturns astring.Type errors often contain this kind of extra explanation telling us why the error happened. They're not perfect, but they're usually helpful.
When defining a variable to hold a function, we can specify its type inline.
>
function add1(n: number): number {return n + 1;}const myAdd1: (n: number) => number = add1;myAdd1(3);Result:
4
>
function double(n: number): number {return 2 * n;}const myDouble: (n: number) => string = double;myDouble(3);Result:
type error: Type '(n: number) => number' is not assignable to type '(n: number) => string'. Type 'number' is not assignable to type 'string'.
This type error is different from the last one. Last time, the function type had a name,
TakesNumberReturnsNumber. This time, it has no name, so the error message contains the full type.In a function definition, we give the arguments names. However, these names aren't part of the type. Only their position matters. We might name an argument
sin a function type, buttextwhen defining the function. That's fine and the code will still type check.>
function downcase(text: string): string {return text.toLowerCase();}type DowncaseFunction = (s: string) => string;const myDowncase: DowncaseFunction = downcase;myDowncase('HELLO');Result:
'hello'
A final note about syntax. TypeScript and JavaScript have two different function syntaxes. There's the older syntax with the
functionkeyword, likefunction myFunction(x). Then there's the newer(x) => ...syntax, often called "arrow functions". When defining a function with an explicit function type, we can only use the newer arrow function syntax:>
const numberToString: (s: number) => string = (// This is the arrow function that we're assigning to `numberToString`.(s) => {return s.toString();});numberToString(5);Result:
This is a limitation of the TypeScript syntax, not the type system. The TypeScript syntax simply doesn't support old-style functions with explicit function types.