Is your async function lacking a return statement?

After completing the development of a new method for a bug I encountered, I noticed something interesting. Despite the fact that there is a potential scenario where the function may not return anything, the compiler did not flag any errors. It got me thinking - why does the compiler stay silent in this case, but raises an issue when using if (false)?

I'm particularly curious about what happens if the condition

if (data && data.json().length)
evaluates to false. Does the function still return a value under such circumstances?

private async getData(items: any[]): Promise<number> {
    for(const item of items) {
        let data = await item.promise;
        if (data && data.json().length) {
            return data.json().findIndex(d => d.fqdn);
        }
    }
}

Your insights would be greatly appreciated.

Answer №1

The TypeScript spec Section 6.3 provides insight into this topic (emphasis added):

An explicitly typed function with a return type that isn't Void, Any, or a union type containing Void or Any must have at least one reachable return statement in its body. An exception is made if the function consists of only a 'throw' statement.

Your function meets this requirement by having a reachable return statement. Placing the return inside an if (false) clause makes it unreachable and doesn't count towards this rule.

If the function exits without a clear return, it implicitly returns a promise for undefined, which is acceptable for Promise<number> when strictNullChecks is off.

This is separate from using async. The following scenarios will compile without errors:

function getData(): number { 
    if (1 + 1 === 3) {
        return 7;
    }
}

As well as:

function getData(): number { 
    if (1 + 1 === 3) {
        return undefined;
    }
}

What occurs if if (data && data.json().length) is false? Does the function return anything?

In such cases, the function returns a promise resolving to undefined since it's flagged as async, leading to promises being returned instead.

Note that when strictNullChecks is enabled, both your function and those mentioned may throw compiler errors due to the invalid use of undefined with number.

Answer №2

Asynchronous functions always result in a promise being returned. If the TypeScript compiler encounters an if (false) statement, it will raise an error because the following return statement is unreachable. In such cases, the function will return a promise containing undefined. A similar issue arises if

data && data.json().length
evaluates to false, but the compiler does not catch this problem.

If a function lacks a default value to return, there is no need for an explicit return statement at the end of the function. However, the function should be appropriately typed:

private async fetchData(results: any[]): Promise<number|void> {
    for(const result of results) {
        let data = await result.promise;
        if (data && data.json().length) {
            return data.json().findIndex(d => d.fqdn);
        }
    }
}

Answer №3

Every time the function is called, it will consistently output a Promise. If the function happens to return implicitly, the Promise will resolve to undefined.

If you have strictNullChecks turned on, this situation should trigger a compiler error.

To observe this, check out the TypeScript playground (and experiment with enabling/disabling strictNullChecks):

async function a(i: boolean): Promise<number> {
    if (i) return 5;
}

If you remove the async keyword and change the return type to number, you'll notice that the behavior remains the same.

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

Crafting Functions That Can Be Typed from Factory Function

My goal is to create a generic function from a factory function that can be typed later. However, I am encountering an issue where I am required to define the return type of the factory function at the time of its definition: export type TypeFunction<T& ...

Enigmatic Cartography Classification

In my attempt to construct a specialized Map-like class that maps keys of one type to keys of another, I encountered a challenge. A straightforward approach would be to create a Map<keyof A, keyof B>, but this method does not verify if the member typ ...

Simple method for adapting async/await function to function smoothly with observables

From my understanding, it's not recommended to use async/await methods in Angular. Therefore, I am exploring alternatives to achieve the desired functionality without using those methods. Currently, I am utilizing the canActivate function which call ...

The guard check may not be enough to prevent the object from being null

Hello, I am facing an issue with the Object is possibly "null" error message in my Node.js + Express application. How can I resolve this problem? REST API export const getOrderReport = async ( req: Request<{}, {}, IAuthUser>, res: Resp ...

Encountering ng build --prod errors following Angular2 to Angular4 upgrade

Upon completing the upgrade of my Angular2 project to Angular4 by executing the following command: npm install @angular/common@latest @angular/compiler@latest @angular/compiler-cli@latest @angular/core@latest @angular/forms@latest @angular/http@latest @an ...

Kendo checkbox toggle issue with switching between true and false states is not functioning correctly

How can I make a button appear when one or more checkboxes are clicked? Currently, the toggle function only activates when I select one checkbox, and then deactivates upon selecting another. Any guidance on improving this functionality would be greatly app ...

Can TypeScript Implement a Dictionary Feature Similar to C#?

Looking for guidance on how to use TypeScript interface to define these C# models: public class PageModel { public long Id { get; set; } public string Name { get; set; } public IDictionary<string, FieldModel> Fields { get; set; } } pu ...

The Firebase EmailPasswordAuthProvider is not a valid type on the Auth object

When working in an Angular2/TypeScript environment, I encountered an error when trying to use the code provided in the Firebase documentation. The error message displayed was "EmailPasswordAuthProvider Does Not Exist on Type Auth". var credential = fireba ...

Error: In Angular Firebase, the type 'string' cannot be assigned to the type 'Date'

I am encountering an error. The following error is shown: "cannot read property 'toDate' of undefined. Without the toDate() | Date." After further investigation, I found: A Timestamp object with seconds=1545109200 and nanoseconds=0. A hel ...

Validation of object with incorrect child fields using Typeguard

This code snippet validates the 'Discharge' object by checking if it contains the correct children fields. interface DischargeEntry { date: string; criteria: string; } const isDischargeEntry = (discharge:unknown): discharge is DischargeEntry ...

What is the best way to implement an onClick event listener in a TypeScript React application?

Is there a way to properly add an onClick event listener to a div element in my code snippet below? useEffect(() => { if (ref.current === null) { return; } const handleClick = (el: HTMLDivElement, e: MouseEvent) = ...

Using Vue js and Typescript to automatically scroll to the bottom of a div whenever there are changes in

My goal is to automatically scroll to the bottom of a div whenever a new comment is added. Here's what I have been trying: gotoBottom() { let content = this.$refs.commentsWrapper; content.scrollTop = content.scrollHeight } The div containing ...

Leveraging the power of react-hook-form in combination with the latest version 6 of @mui

When using MUI v5 date pickers, I utilized the following method to register the input with react-hook-form: <DatePicker ...date picker props renderInput={(params) => { return ( <TextField {...params} ...

How can a child component trigger an event in its parent component?

Currently, I have tabs implemented with a form and a button in tab1. In the parent component, there is an event that deactivates the current tab and activates the next one. Can anyone advise on how to call this event from the child component? gotosecond ...

How can you limit a type reference to a specific file in TypeScript?

Currently, I am working on writing universal JavaScript code that can be used in both Node and browser environments. While most of the code works independent of the environment, there are certain parts where different implementations are required based on ...

The placement of the FirebaseAuth.onAuthStateChanged call in an Angular application is a common concern for developers

Where is the best place to add a global listener initialization call in an Angular app? Take a look at this code snippet: export class AuthService { constructor( private store: Store<fromAuth.State>, private afAuth: AngularFireAuth ) { ...

Passing asynchronous data from method1 to method2 without impacting the functionality of the script responsible for fetching the asynchronous data in method1

When working with TypeScript, I encountered an issue while trying to invoke an external script called SPCalendarPro within a private method that asynchronously fetches data. The script is invoked in the following manner: private _getSPCalendarPro() { con ...

Unexpected issue encountered during the Angular 9 compilation process

Since migrating to Angular 9, I've encountered an issue with my feature branch after a rebase. Trying to switch to develop and update it using pull origin develop, everything seemed fine until I came across this error that's leaving me puzzled: ...

I wonder what the response would be to this particular inquiry

I recently had an angular interview and encountered this question. The interviewer inquired about the meaning of the following code snippet in Angular: code; <app-main [type]="text"></app-main> ...

Issue with Angular2: The [routerLinkActive] directive does not update when using _router.navigate

My app includes several routerLinks that I have styled using [routerLinkActive]="['active']". Everything works perfectly when I click on one of the routerLinks to navigate. However, when I try to navigate using: this._router.navigate( [ thisUrl ...