What is "void" in TypeScript
Tags: programming, typescript, beginners, webdev
Published: 2023-03-10 03:59:23

In this article, you will learn how "void" behaves in the TypeScript code.

## Definition of "void" in the doc
"void" is a kind of type in TypeScript. Let's take a look at the official doc.

> 
`void` is a little like the opposite of any: the absence of having any type at all. You may commonly see this as the return type of functions that do not return a value:
>
```typescript
function warnUser(): void {
  console.log("This is my warning message");
}
```
And then there is another example:

> Declaring variables of type `void` is not useful because you can only assign `null` (only if strictNullChecks is not specified, see next section) or `undefined` to them:

```typescript
let unusable: void = undefined;
// OK if `--strictNullChecks` is not given
unusable = null;
```
Speaking of the second example, in other words, you can assign only `undefined` to the variable in case strictNullChecks is turned on.
But you do not have to remember this because there is no reason to use `void` even if you want a variable to allow to accept only `undefined`. You can use `undefined` type instead.

## How to use "void" with Function Types
To quote from the official documentation, "void" can be expressed as follows:

> the absence of having any type at all

However, this explanation is not enough to utilize this type with function types in real-world development.
Specifically speaking, if you assign `void` to a function type as the return type, the type checker will ignore whatever type is returned by the function.

Here is an example code to demonstrate how void works with Function Types:

```typescript
type returnVoidFuncType = (arg: string) => void;
type returnStringFuncType = (arg: string) => string;

function parentFuncThatWantsVoidCallback(callBack: returnVoidFuncType) {
    callBack("test");
}

function parentFuncThatWantsStringCallback(callBack: returnStringFuncType) {
    console.log(callBack("test"));
}

function childVoidFunc(arg: string) {
    console.log(arg)
}

function childStringFunc(arg: string) {
    return arg;
}

console.log("== Parent Function A ==")
console.log("Expect a callback function that returns 'void'")
parentFuncThatWantsVoidCallback(childVoidFunc);
parentFuncThatWantsVoidCallback(childStringFunc);

console.log("== Parent Function B ==")
console.log("Expect a callback function that returns 'string'")
parentFuncThatWantsStringCallback(childVoidFunc);
parentFuncThatWantsStringCallback(childStringFunc);
```
You can copy&paste the above code to the TypeScript playground if you want to play with that.

Okay, let me explain the code step by step!

We define two types of function types: `returnVoidFuncType` and `returnStringFuncType`.
First, `returnVoidFuncType` is a type whose returned value is `void`. On the other hand, `returnStringFuncType` expects its returned value's type is `string`.
We also define two parent functions that take in these function types as arguments: `parentFuncThatWantsVoidCallback` and `parentFuncThatWantsStringCallback`.

```typescript
type returnVoidFuncType = (arg: string) => void;
type returnStringFuncType = (arg: string) => string;

function parentFuncThatWantsVoidCallback(callBack: returnVoidFuncType) {
    callBack("test");
}

function parentFuncThatWantsStringCallback(callBack: returnStringFuncType) {
    console.log(callBack("test"));
}
```

We then declare two child functions: `childVoidFunc` and `childStringFunc`. 
The first child function, `childVoidFunc` does not return anything (strictly speaking, it returns `undefined` due to JavaScript's default behaviour), whereas the latter returns a string.

```typescript
function childVoidFunc(arg: string) {
    console.log(arg)
}

function childStringFunc(arg: string) {
    return arg;
}
```

Let's see what happens if we pass these child functions to each parent function as a callback function.

```typescript
parentFuncThatWantsVoidCallback(childVoidFunc); // OK
parentFuncThatWantsVoidCallback(childStringFunc); // OK

parentFuncThatWantsStringCallback(childVoidFunc); // Type checker warns
// Argument of type '(arg: string) => void' is not assignable to parameter of type 'returnStringFuncType'.
//  Type 'void' is not assignable to type 'string'.(2345)
parentFuncThatWantsStringCallback(childStringFunc); //OK
```
We can see that `parentFuncThatWantsVoidCallback` can accept both child functions, including the one that returns `string`.

In contrast, `parentFuncThatWantsStringCallback` cannot accept childVoidFunc, whose return type is `void`.

In short, if a type of the returned value of a Function Type is `void`, functions that return any type can be assigned or passed because `void` means "ignoring a type of the returned value".

## Why "void" Ignores Types of a Returned Value?

Please look at the example code below:

```typescript
const array = [1, 2, 3, 4];
const emptyArray = [];

array.forEach((num) => emptyArray.push(num));
```

Examining the type of the forEach method, you can see this type definition:
```
(method) Array<number>.forEach(callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any): void
```
The `forEach` method expects a callback function whose type of the returned value is `void` because the `forEach` method does not want to do anything to the returned value from the callback function. Actually, the type of the returned value from the `push` method is `number` as follows:

```
(method) Array<any>.push(...items: any[]): number
```

This is a good example of understanding why `void` ignores types instead of rejecting them that are not `undefined`.

## Conclusion
As you see above, `void` is often used with Function Types that expect no value will be returned. However, strictly speaking, `void` ignores what types are returned rather than it expects no value should be returned.