There is some ambiguity in the relationship between void
and undefined
, as they are utilized in a few contradictory ways. Typically, void
is used as the return type of a function that does not yield a meaningful value. However, things become complicated when delving deeper into this concept.
For those who call a function returning void
, it implies that there shouldn't be any manipulation of the return value:
declare let voidReturn: () => void;
let v = voidReturn();
v.foo; // Property 'foo' does not exist on type 'void'
v + 2; // Operator '+' cannot be applied to types 'void' and 'number
Since callers agree not to examine the return value of a void
-returning function, it's permissible to substitute any function in its place, regardless of whether it returns a value or not:
voidReturn = () => 123; // okay
Check out the handbook documentation on returning void
for an explanation as to why this is allowed.
From the perspective of callers of functions that return void
, it's as if void
resembles the unknown
type. However, void
existed before unknown
.
On the other hand, for implementers of functions that return void
, the compiler asserts that returning any defined value signifies an error:
function voidReturn2(): void {
return 123; // error!
// Type 'number' is not assignable to type 'void'.(2322)
}
This scenario is almost identical to assigning the function expression voidReturn = () => 123
, but the former is considered erroneous. This inconsistency exists because utilizing a callback function that returns something in a context expecting a void
-returning function is practical, as outlined in the aforementioned handbook. However, directly returning a defined value where a void
result is expected is less useful and more indicative of an error.
Therefore, when developing a function with a return type of void
, avoid returning anything:
function voidReturn3(): void { } // okay
A function lacking a return statement is equivalent to one ending with simply return;
. Consequently, the compiler should also accept this, and it does:
function voidReturn4(): void {
return;
} // okay
If a function doesn't specify a value following return
, it is akin to returning undefined
. The compiler should probably acknowledge this, and it does:
function voidReturn5(): void {
return undefined;
} // okay
Thus, undefined
can be assigned to void
. In situations requiring a type of void
, the only suitable value to use is undefined
.
Despite being somewhat inconsistent and resulting in peculiar behavior, callers of void
returning functions ought to disregard their return values. Yet, they have the option to hold onto a variable of type void
, which can be assigned undefined
but not 123
:
let w = voidReturn();
w = 123; // error
w = undefined; // okay, although unusual
Feel free to explore microsoft/TypeScript#25481 and other discussions such as Why does TypeScript have both `void` and `undefined`? or why is return type `null` (or any other type) assignable to return type `void`? or Typescript: void union type.
Explore code on the Playground