5

I just finished writing the following method for a bug I'm working and was wondering why the compiler did not complain about the following function having the possibility of not returning? If I instead write if (false) the compiler immediately complains about not all paths returning a value.

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

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);
        }
    }
}

Thanks

0

3 Answers 3

6

Section 6.3 of the TypeScript spec explains this (emphasis added):

An explicitly typed function whose return type isn't the Void type, the Any type, or a union type containing the Void or Any type as a constituent must have at least one return statement somewhere in its body. An exception to this rule is if the function implementation consists of a single 'throw' statement.

Your function has one reachable return statement, so it satisfies this requirement. If you place the return inside an if (false), it isn't considered, because it is unreachable.

In the event that it terminates without explicitly returning, it will implicitly return a promise for undefined, which is an allowed value for Promise<number> when the strictNullChecks option is not enabled.

This is unrelated to async. The following also compiles without error:

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

As does this:

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

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

It returns a promise that resolves to undefined, because it is marked as async, and async functions always return promises.

Note that (as Tom Fenech pointed out before me), using the strictNullChecks causes both your function and the ones in this answer to produce compiler errors, because undefined is not considered to be a possible value of number when that option is enabled.

Sign up to request clarification or add additional context in comments.

Comments

2

async functions always return a promise. In case of if (false) TypeScript compiler complains, because return statement is unreachable. The function returns a promise of undefined in this case. This also happens if data && data.json().length is false, but this problem cannot be detected by the compiler.

The function doesn't require explicit return at the end of the function if it has no default value to return, but it should be typed accordingly:

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

2 Comments

TypeScript doesn't care if the function returns a promise of undefined (unless strictNullChecks are enabled, which they aren't in OP's case). It cares whether the function has at least one (reachable) return statement that returns a type that can be coerced into number or Promise<number>. You can observe this by replacing the return statement in OP's example with return undefined.
I believe strictNullChecks should be assumed in any recent TS answer, but it doesn't matter here. I updated the answer to make it clear that function returns a promise of undefined is not a consequence of return statement is unreachable. TypeScript doesn't care about that, but a user does. The point is that Promise<number> is not correct type for a function that can potentially return a promise of undefined.
0

The function always returns a Promise. In the case that the function implicitly returns, the Promise will resolved to undefined.

With strictNullChecks enabled, this should result in a compiler error.

You can see this in the TypeScript playground (try toggling strictNullChecks in the options):

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

You can also remove the async keyword and change the return type to number and you will see the same behaviour.

3 Comments

I'm pretty sure this has nothing to do with the function always returning a promise, but it's true that strictNullChecks causes it to have a compiler error.
I'm not saying it is behaviour specific to the async keyword, I just used the same types as in the question. I have edited to make that explicit.
Ok, but in OP's example, the function body is actually returning (as far as the compiler knows) any. It has no way of determining what type data.json().findIndex(d => d.fqdn) is.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.