In TypeScript, you can annotate a function as returning void
:
function fn1(): void { // OK } function fn2(): void { // Error return 3; }
You can also annotate a function to return undefined
:
function fn3(): undefined { // OK return; } function fn4(): undefined { // Error return 3; }
So it seems that if you call a function returning void
, you'll always get back the value undefined
. Yet you can't write this code:
function fn5(): void { } let u: undefined = fn5(); // Error
Why isn't void
just an alias for undefined
? Does it need to exist at all?
void is not the same as any , nor the same as undefined .
Introduction to TypeScript void type The void type denotes the absence of having any type at all. It is a little like the opposite of the any type. Typically, you use the void type as the return type of functions that do not return a value.
The void operator evaluates the given expression and then returns undefined .
The difference is that some browsers allow you to overwrite the value of undefined . However, void anything always returns real undefined. void is an operator and not a function so you dont have to use void() .
void
has special meaning in function return types, and is not an alias for undefined
. Thinking of it this way is very wrong. Why?
The intent of void
is that a function's return value will not be observed. This is very different from will be undefined
. It's important to have this distinction so that you can properly describe functions like forEach
. Let's consider a freestanding version of Array#forEach
, written with undefined
instead of void
in the callback return position:
declare function forEach<T>(arr: T[], callback: (el: T) => undefined): void;
If you tried to use this function:
let target: number[] = []; forEach([1, 2, 3], el => target.push(el));
You'd get an error:
Type "number" is not assignable to type "undefined"
This is a correct error - you said you wanted a function that returned the value undefined
, but you actually provided a function that returned the value number
because that's what Array#push
returns!
Using void
instead means that forEach
promises not to use the return value, so it can be called with a callback that returns any value
declare function forEach<T>(arr: T[], callback: (el: T) => void): void; let target: number[] = []; // OK forEach([1, 2, 3], el => target.push(el));
Why not just use any
? If you're actually the one implementing forEach
, you really don't want that - having an any
floating is a dangerous thing that can defeat typechecking very easily.
The corollary to this is that if you have some function expression whose return type is void
, you cannot say with any certainty that the result of invoking that function is undefined
.
void
is not an alias for undefined
and an expression of type void
may have any value, not just undefined
In a function body whose return type is explicitly listed as void
, TypeScript will stop you from "accidently" returning a value, even though this wouldn't create a type system violation. This is helpful for catching bugs that appear from a refactoring:
// Old version function fn(arr: number[]): void { const arr1 = arr.map(x => { return 3; }); } // New version function fn(arr: number[]): void { for (const x of arr) { // Oops, meant to do something else return 3; }; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With