What is the reason behind TypeScript's lack of reporting an incorrect function return type?

It's surprising to see that TypeScript 4.4.3 does not identify an invalid type for the callback function. It makes sense when the function returns a "non-promise" type, but when it returns a Promise, one would expect TypeScript to recognize that we need to wait for it to resolve. setCallback requires a function that returns void, but in this case, it is being used with a function that returns Promise<void>, indicating that there is something to be awaited.

const setCallback = (cb: () => void): void => {
    cb();
};

const callback = (): Promise<void> => {
    return new Promise(resolve => {
        setTimeout(() => resolve(), 100);
    });
}

setCallback(callback);

TS Playground

Answer №1

TypeScript is indifferent

When using setCallback(), all you need to provide is a reference to a function, which can be of any type. As long as the function itself is not invoked, TypeScript considers it an object. This means that TypeScript will not throw a TypeError as long as your function expects an object.

If the object is called, TypeScript will identify any mismatches and provide a TypeError accordingly.

  1. Passing by reference

In Pass by Reference, a function receives the reference or address of a variable as its argument. Modifying the argument within the function impacts the original variable passed from outside the function. In JavaScript, objects and arrays are examples of entities passed by reference.

  1. Understanding Functions (MDN)

A function serves as a "subprogram" callable by external code or even internally in the case of recursion. Similar to a program, a function consists of statements forming the function body. Data can be sent to a function for processing, with the function returning a value upon completion.

Functions in JavaScript are treated as first-class objects, possessing properties and methods akin to regular objects. However, what sets them apart is their invocable nature; functions can be executed like Function objects to perform specific tasks.

Illustration: Example 1

Due to limitations regarding void functions and the impossibility of utilizing .then(), I had to resort to creating an IIFE to enable async functionality. Surprisingly, this approach functions properly despite anticipating a callback of void type.

const setCallback = (cb: () => void): void => {
    (async () => await cb())().then(() => console.log("Hi"));
};

const callback = (): Promise<number> => {
    return new Promise(resolve => {
        setTimeout(() => resolve(0), 100);
    });
}

setCallback(callback);

Exploring Further: Example 2

If an attempt is made to execute the function with a return type of Promise:

The 'Promise' argument does not align with the expected '() => void' parameter. The 'Promise' type lacks compatibility with the signature '(): void'.

This error highlights the discrepancy in Function signatures.

const setCallback = (cb: () => void): void => {
    (async () => await cb())().then(() => console.log("Hi"));
};

const callback = (): Promise<number> => {
    return new Promise(resolve => {
        setTimeout(() => resolve(0), 100);
    });
}

setCallback(callback());

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

Implying generics at a later time, not during instantiation / altering the type of a generic

If we consider the example provided, is there a way to instruct the typescript compiler that the return type of baz must be string, since it can be inferred from foo.a('aString') that it's a string? const fn = <T,S>()=>{ let s: S ...

Modify visibility within a subclass

Is there a way to modify property visibility in a child class from protected to public? Consider the following code snippet: class BaseFoo { protected foo; } class Foo extends BaseFoo { foo = 1; } new Foo().foo; It seems that this change is pos ...

Tips for accessing an item from a separate TypeScript document (knockout.js)

In the scenario where I need to utilize an object from another TypeScript file, specifically when I have an API response in one.ts that I want to use in two.ts. I attempted exporting and importing components but encountered difficulties. This code snippe ...

Angular 5 Image Upload - Transfer your images with ease

I am having trouble saving a simple post in firebase, especially with the image included. This is my current service implementation: uploadAndSave(item: any) { let post = { $key: item.key, title: item.title, description: item.description, url: '&a ...

Using TypeScript, a parameter is required only if another parameter is passed, and this rule applies multiple

I'm working on a concept of a distributed union type where passing one key makes other keys required. interface BaseArgs { title: string } interface FuncPagerArgs { enablePager: true limit: number count: number } type FuncArgs = (Fu ...

Group data by two fields with distinct values in MongoDB

I have developed a Typescript Node.js application and I am looking to organize documents by two fields, "one_id" and "two_id", based on a specific "one_id" value. Below is the data within my collection: { "_id":"5a8b2953007a1922f00124fd", "one_id ...

How can I implement a scroll bar in Angular?

I am facing an issue with my dialog box where the expansion panel on the left side of the column is causing Item 3 to go missing or appear underneath the left column when I expand the last header. I am looking for a solution to add a scroll bar so that it ...

"Enhance your development experience with the TypeScript definitions for the Vue 2 plugin

Currently, I am utilizing VSCode alongside TypeScript classes for developing Vue 2 components. You can check out more information at: vuejs/vue-class-component. Within my present project, I make use of plugins like vue-i18n for handling translations of la ...

Utilizing the input element to modify the font color of the title upon clicking the button

I've been honing my skills in Angular and facing an issue with altering the font color of a variable called title. I'm struggling to figure it out. Take a look at the code snippet from tools.component.ts: [...] title: string = 'Add note ...

Navigating to the main directory in Angular 2

I am currently diving into the world of Angular 2 and attempting to create my very first application. I am following a tutorial from Barbarian Meets Coding to guide me through the process. Following the steps outlined in the tutorial, I have set up my appl ...

Unable to assign to 'disabled' as it is not recognized as a valid attribute for 'app-button'

How to link the disabled property with my button component? I attempted to add 'disabled' to the HTML file where it should be recognized as an input in the button component (similar to how color and font color are recognized as inputs) ... but ...

The ts-mocha test does not play well with the use of node-fetch library

I have set up ts-mocha and node-fetch to run a unit test, but I am encountering the following error: TypeError: Unknown file extension ".ts" for ... The content of the file is as follows: import fetch from 'node-fetch'; export defau ...

Why does the data appear differently in Angular 9 compared to before?

In this particular scenario, the initial expression {{ bar }} remains static, whereas the subsequent expression {{ "" + bar }} undergoes updates: For example: two 1588950994873 The question arises: why does this differentiation exist? import { Com ...

Steps to automatically set the database value as the default option in a dropdown menu

I'm in need of assistance with a project that I'm working on. To be completely honest, I am struggling to complete it without some help. Since I am new to Angular and Springboot with only basic knowledge, I have hit a roadblock and can't mak ...

Transitioning from Global Namespace in JavaScript to TypeScript: A seamless migration journey

I currently have a collection of files like: library0.js library1.js ... libraryn.js Each file contributes to the creation of a global object known as "MY_GLOBAL" similarly to this example: library0.js // Ensure the MY_GLOBAL namespace is available if ...

What is the process for including a custom Jasmine matcher definition in Typescript?

I've been searching around for information on creating custom Jasmine matchers using TypeScript and it seems like a common issue. However, none of the solutions I've come across have worked for me. My setup includes: { "typescript": "2.3.2", ...

The onNodeContextMenuSelect function does not seem to be functioning properly within the p-tree

<p-tree [value]="files" selectionMode="single" (onNodeContextMenuSelect)="showContect($event)" > </p-tree> Whenever I right click, the event doesn't seem to be triggering. Instead, the default browser c ...

Retrieve new data upon each screen entry

After running a query and rendering items via the UserList component, I use a button in the UserList to run a mutation for deleting an item. The components are linked, so passing the deleteContact function and using refetch() within it ensures that when a ...

Utilizing WebPack 5 in conjunction with Web workers in a React/Typescript environment

Can someone help me figure out how to make a web worker function properly with create-react-app, Typescript, and Webpack 5? I've been struggling with limited documentation and can't seem to find a clear explanation. I'm trying to avoid using ...

error TS2304: The term 'MediaRecorder' is not recognized

How can I add audio recording capability to my Angular application using media recorder? Unfortunately, I am encountering the following error: Error TS2304: 'MediaRecorder' cannot be found If anyone knows a solution for this issue, your help w ...