What is "void" in TypeScript
Tomohiro Yoshida
Posted on March 10, 2023
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");
}
And then there is another example:
Declaring variables of type
void
is not useful because you can only assignnull
(only if strictNullChecks is not specified, see next section) orundefined
to them:
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:
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
.
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.
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.
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:
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.
Posted on March 10, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.