How can we create a unique type in Typescript for a callback that is void of any return value?

When it comes to safe callbacks, the ideal scenario is for the function to return either undefined or nothing at all.

Let's test this with the following scenarios:

declare const fn1: (cb: () => void) => void;
fn1(() => '123'); // no error

Unfortunately, this didn't work out as expected. It seems that string is not compatible with void.

Next up:

declare const fn2: (cb: () => unknown) => void;
fn2(() => '123'); // no error

To our surprise, the same issue occurred. Let's try something else.

Testing again:

declare const fn3: (cb: () => undefined) => void;
fn3(() => '123'); // error: Type 'string' is not assignable to type 'undefined'

Progress! An error was thrown this time. Let's proceed with this approach:

fn3(() => undefined); // okay
fn3(() => {}); // error: Type 'void' is not assignable to type 'undefined'

This doesn't meet our requirements.

Considering a different route:

declare const fn4: (cb: () => void | undefined) => void;
fn4(() => undefined); // okay
fn4(() => { }); // okay
fn4(() => '123'); // error: Type 'string' is not assignable to type 'undefined'

Success! This seems like a viable solution.

However, why does void allow string, while void | undefined does not? Is this a bug?

Is it safe to assume this behavior will remain consistent in future TypeScript updates? Are there better alternatives to achieve the same outcome?

Answer №1

UPDATED 2

If you want to define a callback that shouldn't have any arguments, not even optional ones, and should not return anything, here's how you can do it:

type callback = (...a: void[]) => void | undefined;

const func = (a: callback) => { 
    a();
};

const test1 = func(() => { }); // works
const test2 = func((a?: string) => { }); // fails
const test3 = func(() => '5'); // fails

UPDATED

After discussions in the comments, it was determined that the goal is not just to ignore the return value of the callback, but rather to guarantee that it won't return anything else so it can be safely passed to other functions that rely on this behavior.

In this case, I suggest adding a small helper function that truly ignores any returned value.

const shutUp = <T extends (...args: any) => void>(func: T): ((...args: Parameters<T>) => void) => (...args: any[]) => {
    func(...args);
};

const shutUpNoArgs = <T extends () => void>(func: T): ((...args: never) => void) => () => {
    func();
};

const test = shutUp((a: string) => 5);

const result1 = test('5'); // works, result1 is void.
const result2 = test(5); // doesn't work.

_.forEach(data, shutUp(callback));

ORIGINAL

There's no need to be overly strict or worried about these details.

The use of void implies that we don't consider the return value, which is fine if we are not depending on it.

It's similar to rejecting a function because it doesn't require our a argument, even though it can still be functional without it.

declare const fn1: (cb: (a: string) => void) => void;

fn1(() => {
}); // No error, even when 'a' is not used in the callback.

For further information, refer to the TypeScript documentation on void.

void is somewhat like the opposite of any: indicating the absence of having any specific type at all.

Therefore, its behavior remains consistent, and it can be utilized in union with undefined as needed.

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

Typescript type for selecting only string[] keys in an object

I am looking for a specific type: interface Filter<P extends object> { label: string; options: FilterOption[]; key: StringArrayKeyOf<P>; } The definition of StringArrayKeyOf is as follows: type StringArrayKeyOf<T extends object> = ...

Converting Data Types in Typescript

So I'm working with Data retrieved from a C# Rest Server. One of the values in the array is of type Date. When I try to perform calculations on it, like this: let difference = date1.getTime() - date2.getTime(); I encounter the following error messag ...

Simple steps to turn off error highlighting for TypeScript code in Visual Studio Code

Hey there! I've encountered an issue with vscode where it highlights valid code in red when using the union operator '??' or optional chaining '?.'. The code still builds without errors, but vscode displays a hover error message st ...

Type of JavaScript map object

While exploring TypeScript Corday, I came across the following declaration: books : { [isbn:string]:Book}={}; My interpretation is that this could be defining a map (or dictionary) data type that stores key-value pairs of an ISBN number and its correspon ...

Is there a way to verify if an object adheres to a specified interface?

Let's say I have a custom interface called MyInterface Is there a built-in method in TypeScript that allows checking if an object adheres to the MyInterface ? Something similar to using instanceof but for interfaces instead of classes. ...

Unable to access 'this' within a custom operator in RxJs

I developed a unique operator that utilizes the this keyword, but I am encountering an issue where it always returns undefined. Even though I used bind to pass this into the function. My special operator function shouldLoadNewOptimizationData() { retu ...

The method beforeEach in angular2/testing seems to be failing as it is not

Currently, I am utilizing Gulp, Gulp-Jasmine, and SystemJS to conduct tests on an Angular2 demo application. The setup is fairly straightforward. I have successfully implemented a System.config block and loaded the spec file. However, I encounter an error ...

`Is there a way to assign multiple parameters to HttpParams within Angular 5?`

I'm attempting to send multiple parameters to HttpParams in Angular 5 using the approach below: paramsObject: any params = new HttpParams(); for (let key in paramsObject) { params.set(key, paramsObj ...

"Retrieving an element from an array may result in a value of

While going through an array of objects in my Angular component class, I faced a strange issue where the properties kept showing up as undefined. The function responsible for this behavior looks like this: upload(): void { const { fileHandles, related ...

The component 'ProtectRoute' cannot be utilized within JSX

While using typescript with nextjs, I encountered an issue as illustrated in the image. When I try to use a component as a JSX element, typescript displays the message: ProtectRoute' cannot be used as a JSX component. import { PropsWithChildren } from ...

ReactForms Deprication for NgModel

According to Angular, certain directives and features are considered deprecated and could potentially be removed in upcoming versions. In a hypothetical scenario, let's say I am using NgModel with reactive forms, which Angular has marked as deprecate ...

Learn the art of generating multiple dynamic functions with return values and executing them concurrently

I am currently working on a project where I need to dynamically create multiple functions and run them in parallel. My starting point is an array that contains several strings, each of which will be used as input for the functions. The number of functions ...

Is there a way to achieve region collapsing and expanding using #region / #endregion in TypeScript within Visual Studio Community Edition 2019?

For a while now, we've been utilizing "region collapsing" in TypeScript as shown below: //#region GUI handlers ...code related to handling GUI events... //#endregion This method has functioned well in VS2015 CE and VS2017 CE, with a small "-" or "+" ...

Can you explain the purpose of the "letter:" included in the code and how it is utilized?

g: function testFunction() { return true; } h: function anotherTestFunction() { } i: console.log('test') I'm intrigued by the mystery of this code snippet. As is written, I am executing it in NodeJS version 16 or higher and trying to un ...

Discovering the permissible array values from numerous arrays inside an object using TypeScript

I have an object with multiple arrays of strings (hardcoded). I want to specify that only strings from that object are allowed in another empty array. In a simple non-nested scenario, I'm achieving this with typeof someArray[number][]. So, I hoped to ...

What is the best way to define a global variable in TypeScript and access it throughout a Vue application?

In my main.ts file, I am looking to define a variable that can be accessed in all Vue files. Within my sfc.d.ts file, the following content is included: declare module '*.vue' { import Vue from 'vue' export default Vue } declar ...

Guide to integrating a native web component into Vue3

After creating the renderComponent method to display a webcomponent, I attempted to use it in my componentView.vue file. export function renderComponent(el: Element, component: Component,props: VNodeProps,appContext: AppContext){ let vnode: VNode | undefin ...

Having Trouble Setting Default Value in React Typescript MUI Autocomplete

I am encountering an issue with my React and Typescript code using MUI with the use of hook form. The problem arises when trying to set a default value for an Autocomplete field, resulting in the following error message: I am seeking assistance in resolvi ...

Important notice: It is not possible to assign refs to function components. Any attempt to do so will result in failure. If you intended to assign a ref, consider

My console is showing a warning when I use the nextJs Link component. Can someone assist me in resolving this issue and providing an explanation? Here is the message from the console: https://i.stack.imgur.com/jY4FA.png Below is a snippet of my code: im ...

Utilize string values as identifiers in type declarations

My Props type declaration currently looks like this: type Props<FormData> = { formData: FormData, sectionNme: keyof FormData, name: string } However, I am trying to modify it to look more like the following: type Props<FormData> = ...