How is it that void can be assigned undefined?

According to the documentation on typescript, it states that "the one exception being that undefined is also assignable to void".

Source

Strict null checking mode specifies that null and undefined values are not within the domain of every type and can only be assigned to themselves and any (with the exception of undefined being assignable to void as well). In regular type checking mode, T and T | undefined are treated as synonymous due to undefined being considered a subtype of any T. However, in strict type checking mode, they are distinct types and only T | undefined allows for undefined values. The same principle applies to the relationship between T and T | null.

What is the reason behind this specific exception made for void?

This source does not provide an answer. Please refrain from suggesting it.

Answer №1

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Disable and grey out the button while waiting for the Observable to broadcast successfully

component.html <button mat-raised-button color="primary" type="submit"> <mat-icon>account_box</mat-icon> <span *ngIf="!loading">&nbsp;&nbsp;&nbsp;Register</span> <span * ...

Error message: Invariant Violation: Portal.render() being caused by semantic-ui-react Basic Modal

As part of enhancing an existing React component, I attempted to include a basic modal (link to documentation). Everything was working well without the modal, but once I added it in following the semantic-ui-react guidelines, I encountered a runtime error ...

Exploring subclasses in TypeScript

When working with TypeScript and defining an interface like the one below: export interface IMyInterface { category: "Primary" | "Secondary" | "Tertiary", } Can we access the specific "sub types" of the category, such as ...

Leverage the power of Angular's library dependency injection with the @inject

I am currently working on a project that involves a library. Within one of the classes in this library, I am attempting to provide a service using @optional, @host, and @inject decorators with an injection token. In the parent component, I have the optio ...

Encountered an issue when attempting to send data using this.http.post in Angular from the client's perspective

Attempting to transfer data to a MySQL database using Angular on the client-side and Express JS on the server-side. The post function on the server side works when tested with Postman. Here is the code snippet: app.use(bodyParser.json()); app.use(bodyPa ...

The Typescript "and" operator is used for combining multiple conditions

I'm having difficulty understanding the functionality of the & operator in TypeScript. I recently encountered this code snippet: type IRecord<T> = T & TypedMap<T>; Can someone explain what this operator does and how it differs fr ...

Developing client-side components with NextJS

I want to develop a single-page landing page where users can upload videos and there's a file size limit check before the upload. In my src/app/page.tsx file, I have the following code: import React from 'react'; import FileUpload from &apo ...

Troubleshooting issue with React and Material UI Table pagination display

Issue with Material UI Table Display When Changing Pages When receiving an array of Artist Objects through props to create a checklist table, I encounter some display issues. The table works fine initially, but when changing pages or sorting, more rows th ...

How can we automate the process of assigning the hash(#) in Angular?

Is it possible to automatically assign a unique hash(#) to elements inside an ngFor loop? <div *ngFor="let item of itemsArray; index as i"> <h3 #[item][i]> {{ item }} </h3> </div> I would like the outp ...

Utilize a variable within a regular expression

Can the variable label be used inside a regex like this? const label = 'test' If I have the regex: { name: /test/i } Is it possible to use the variable label inside the regex, in the following way? { name: `/${label}/i` } What do you think? ...

issue TS2322: The function returns a type of '() => string' which cannot be assigned to type 'string

I have recently started learning Angular 6. Below is the code I am currently working on: export class DateComponent implements OnInit { currentDate: string = new Date().toDateString; constructor() { } ngOnInit() { } } However, I am encounterin ...

Identifying row expansion in ngx-datatable: detecting expand status on row click

Is there a way to determine if a line has already been expanded when using the toggle feature? When you click on a line, it expands and shows the details. Here is some code in HTML: <ngx-datatable #dataTable ... (select)='onRowSelect($eve ...

What is the best way to declare a TypeScript type with a repetitive structure?

My data type is structured in the following format: type Location=`${number},${number};${number},${number};...` I am wondering if there is a utility type similar to Repeat<T> that can simplify this for me. For example, could I achieve the same resul ...

Angular 5 is throwing an error that says: "There is a TypeError and it cannot read the property 'nativeElement' because it

Being aware that I may not be the first to inquire about this issue, I find myself working on an Angular 5 application where I need to programmatically open an accordion. Everything seems to function as expected in stackblitz, but unfortunately, I am enco ...

The attribute 'tableName' is not found within the 'Model' type

Currently in the process of converting a JavaScript code to TypeScript. Previously, I had a class that was functioning correctly in JS class Model { constructor(input, alias) { this.tableName = input; this.alias = alias; } } Howev ...

Gain insights on Stripe Webhooks with Firebase Functions and Node.js

I've been struggling to integrate Firebase functions with Stripe webhooks for listening to events. Take a look at my code: exports.stripeEvents = functions.https.onRequest((request, response) => { try { const stripeSignature = request. ...

Can anyone guide me on implementing getServerSideProps in a TypeScript NextPage component?

I've come across a page that I'd like to replicate, with the code sourced from https://github.com/dabit3/nextjs-lit-token-gating/blob/main/pages/protected.js: import Cookies from 'cookies' import LitJsSdk from 'lit-js-sdk' ex ...

Utilizing useLocation for Defining Text Styles

I'm currently integrating TypeScript into my project, but I'm encountering an error related to 'useLocation' in my IDE. Any thoughts on what might be causing this issue? import React from "react"; import { useHistory, useLocat ...

Can parameters with identical union types in a function signature be streamlined to contain only the exact same subtypes using generic types?

// defining a type Combinable with string or number as possible values type Combinable = string | number; // function to check if parameter is a string function isString(param: unknown): param is string { return typeof param === "string"; } /** * Func ...

Steps to dynamically include a marker on a Google Maps component using HTTPGET in Angular 6

I am currently working on an Angular 6 application that involves integrating the Google Javascript API with AGM. So far, the map functions well except for dynamically adding markers using an http get request. Here is a snippet of the component.html: < ...