How to Type Functions in TypeScript
We can break down typing functions in TypeScript into two parts: typing the parameters and typing the return value. For best coverage, you want to type both. Most commonly, functions are typed inline. This means types are added as part of the function. Let's take a look at an example.
const stringify = (value: any): string => JSON.stringify(value)
This simple function turns a value into a string. It accepts any value and returns a string. When it comes to typing parameters, we can define the parameter types next to the name of the parameter after a colon. The return type of the function always comes after the parentheses. The same annotation applies to multiple parameters too.
const add = (a: number, b: number): number => a + b
// β This will throw:
// Argument of type 'string' is not assignable to parameter of type 'number'. ts(2345)
add('1', '2')
// β This will throw:
// Property 'replace' does not exist on type 'number'. ts(2339)
add(1, 2).replace('0', '*')
As expected, this will prevent unexpected types to be passed into the function, as well as using the return type in unexpected places, or calling non-existing functions on it.
Typing Object Parameters
You may also come across one of the following syntaxes when defining types for destructured objects:
// Inline types
const slider = ({
selector,
animation,
images
}: {
selector: string
animation: 'slide' | 'fade'
images: string[]
}) => {}
// Separated types
type Props = {
selector: string
animation: 'slide' | 'fade'
images: string[]
}
const slider = ({ selector, animation, images }: Props) => {}
In the first example, we inlined the types, while in the second example for brevity β especially common in React β we outsourced it into a type
called Props
, and assigned it to the parameters. We can use the void
type when a function doesn't return anything. This is also true for the above case where we rather create something as opposed to returning a value.
// Use void if a function doesn't return anything
const slider = (...): void => {}
const animate = (): void => {}
Defining Types Separately
As shown in the above example, types on the other hand can also be defined separately. Let's take the very first code as an example.
// Inlining types
const stringify = (value: any): string => JSON.stringify(value)
// Defining types separately
type Stringify = (value: any) => string
const stringify: Stringify = (value) => JSON.stringify(value)
In the second case, we defined a type
called Stringify
and assign it to the stringify function. In this case, we can leave out the types for the parameters as well as the return type, as the Stringify
type already defines it.
Notice the difference in syntax. When using separate types, we need to call the type after the name of the function. Calling it after the parameters would act as a return type.
Summary
In summary, when working with function types in TypeScript we should keep the following points in mind:
- Both parameters and return types can be typed separately
- Types can be inlined or defined separately
- Use the type after the function name if you are outsourcing types
- Avoid inlining types for destructured object
- Use
void
for no return types
Rocket Launch Your Career
Speed up your learning progress with our mentorship program. Join as a mentee to unlock the full potential of Webtips and get a personalized learning experience by experts to master the following frontend technologies: