Everyday TypeScript: ReturnType and Parameters
Welcome to the ReturnType and Parameters 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 how to write function types:
Here's a code problem:
This code defines a
StringFunctiontype, but the actual type is missing. Add a type that means "a function that takes no arguments and returns a string".type StringFunction = () => string;const returnsHello: StringFunction = () => 'hello';const hello: string = returnsHello();hello;- Goal:
'hello'
- Yours:
'hello'
Sometimes we want to extract an existing function's return type or parameter types. TypeScript can do both of those! We can use TypeScript's generic
ReturnTypetype to get the return type. It takes a function type as its type parameter, then gives us the return type of that function.>
type StringFunction = () => string;type OurReturnType = ReturnType<StringFunction>;const hello: OurReturnType = 'hello';hello;Result:
'hello'
>
type StringFunction = () => string;type OurReturnType = ReturnType<StringFunction>;const hello: OurReturnType = 123;hello;Result:
type error: Type 'number' is not assignable to type 'string'.
Note that error message. We may have defined our type as
ReturnType<StringFunction>, but it's just an alias for the familiar'string'type!TypeScript also provides a
Parameterstype. It takes a function type and gives us a tuple type back. (As a refresher, tuple types are arrays of fixed length.) Each tuple element is one of the function's parameter types, in the same order they were declared.>
/* Note that DoubleFunction is a type, not a function. It doesn't double* numbers. Instead, it says "a function that doubles numbers will return* a number". */type DoubleFunction = (n: number) => number;type DoubleParameters = Parameters<DoubleFunction>;const args: DoubleParameters = [5];args;Result:
[5]
>
type DoubleFunction = (n: number) => number;type DoubleParameters = Parameters<DoubleFunction>;const args: DoubleParameters = 5;args;Result:
type error: Type 'number' is not assignable to type '[n: number]'.
When we use
Parameterson a function with multiple parameters, we get a tuple with multiple elements.>
type AddFunction = (x: number, y: number) => number;type AddParameters = Parameters<AddFunction>;const args: AddParameters = [1, 2, 3, 4, 5];args;Result:
type error: Type '[number, number, number, number, number]' is not assignable to type '[x: number, y: number]'. Source has 5 element(s) but target allows only 2.
>
type AddFunction = (x: number, y: number) => number;type AddParameters = Parameters<AddFunction>;const args: AddParameters = [1, 2];args;Result:
[1, 2]
We can index into tuple types to get the type of an individual tuple element. When using
Parameters, that lets us get the type of just one function argument.Here's a code problem:
In the code below, we want to create a variable that holds the parameters for an "add" function. However, the type is currently missing. Use the
Parametersgeneric type to get the function type's parameter type, using it as the type for theargsvariable. (You don't need to modify any of the existing code; you only need to add the missing type.)type AddFunction = (x: number, y: number) => number;const args: Parameters<AddFunction> = [10, 20];args;- Goal:
[10, 20]
- Yours:
[10, 20]
What about rest parameters? (As a reminder, rest parameters are a JavaScript and TypeScript feature where functions can take arbitrarily many arguments, which are collected in an array.) When
Parametersencounters rest parameters, it sensibly treats them as an array type. For the parameter type of(...args: string[]) => number, it gives usstring[].>
type CountStringsFunction = (...args: string[]) => number;type CountParameters = Parameters<CountStringsFunction>;const strings: CountParameters = ['a', 'b', 'c'];strings;Result:
['a', 'b', 'c']
>
type CountStringsFunction = (...args: string[]) => number;type CountParameters = Parameters<CountStringsFunction>;const strings: CountParameters = ['a'];strings;Result:
['a']
>
type CountStringsFunction = (...args: string[]) => number;type CountParameters = Parameters<CountStringsFunction>;const numbers: CountParameters = [1, 2, 3];numbers;Result:
type error: Type 'number' is not assignable to type 'string'.
An important note: you've probably heard the terms "parameters" and "arguments" used interchangeably. Then why is this type called
Parametersand notArguments? The reason is that the two words have different meanings when we talk about programming languages in a formal way.A parameter is part of a function's definition, like the
ninfunction double(n: number). An argument is a value that we pass when calling a function, like the5indouble(5). Many programmers call both of these "arguments" in everyday conversation. Compilers and other programming language tools like TypeScript need to avoid ambiguity, so they usually distinguish between parameters and arguments.TypeScript adds a lot of new syntax like
type X = ...andconst x: numberandType1 | Type2. It's tempting to think thatReturnTypeandParametersare special syntax as well, but they're not! We could write them ourselves if we wanted to. In fact, these types are defined in a regular ".ts" file that comes with TypeScript.If you're curious about how this works, here's the actual definition of
ReturnTypein our TypeScript installation. (We found this in the file "node_modules/typescript/lib/lib.es5.d.ts".) It uses a few advanced TypeScript features that you may not have seen yet, and utility types tend to be strange at the best of times, so don't worry if it doesn't make sense.>
type ReturnType<T extends (...args: any) => any> =T extends (...args: any) => infer R ? R : any;One thing was conspicuously absent in this lesson. We didn't use
ParametersorReturnTypeon an actual defined function, likefunction f(...). Instead, we only used them on function types like() => number. To use these types on actual functions, we'll need thetypeofoperator. We cover that topic in our Advanced Typescript course, but we strongly recommend finishing this course before moving on to Advanced TypeScript!