DEV Community

Cover image for What is "void" in TypeScript
Tomohiro Yoshida
Tomohiro Yoshida

Posted on • Updated on

What is "void" in TypeScript

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:

function warnUser(): void {
  console.log("This is my warning message");
}
Enter fullscreen mode Exit fullscreen mode

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:

let unusable: void = undefined;
// OK if `--strictNullChecks` is not given
unusable = null;
Enter fullscreen mode Exit fullscreen mode

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:

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);
Enter fullscreen mode Exit fullscreen mode

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.

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

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

function parentFuncThatWantsStringCallback(callBack: returnStringFuncType) {
    console.log(callBack("test"));
}
Enter fullscreen mode Exit fullscreen mode

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.

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

function childStringFunc(arg: string) {
    return arg;
}
Enter fullscreen mode Exit fullscreen mode

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

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
Enter fullscreen mode Exit fullscreen mode

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:

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

array.forEach((num) => emptyArray.push(num));
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)