Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Surprising Not all code paths return a value #18319

Open
wycats opened this issue Sep 7, 2017 · 8 comments
Open

Surprising Not all code paths return a value #18319

wycats opened this issue Sep 7, 2017 · 8 comments
Labels
Help Wanted You can do this Suggestion An idea for TypeScript
Milestone

Comments

@wycats
Copy link

wycats commented Sep 7, 2017

TypeScript Version: 2.5.2

Code

type AsyncFunction<T> = () => Promise<T>;

const f: AsyncFunction<number | void> = async () => {
  if (Math.random()) {
    return 1;
  }
};

Expected behavior:

No tsc errors.

Actual behavior:

const f: AsyncFunction<number | void> = async () => {
//                                      ~~~~~~~~~~~~~ [ts] Not all code paths return a value.

  if (Math.random()) {
    return 1;
  }
};

Notably, when using return-type annotation, this error does not occur:

async function a(): Promise<number | void> {
  if (Math.random()) {
    return 1;
  }
}

const b = async (): Promise<number | void> => {
  if (Math.random()) {
    return 1;
  }
};

In our real-world scenario, it would not be sufficient to look for this syntactic pattern. Rather, the fact that the async function is assigned to a union containing void should be the trigger that silences this error.

@RyanCavanaugh
Copy link
Member

Doesn't require async

type fn = () => (void | number);

var x: fn = () => {
  if (Math.random()) {
    return 1;
  }
}

I'm not really sure if this error is "unexpected" or not. It's controlled by the "No implicit returns" flag and this is definitely an implicit return.

@RyanCavanaugh RyanCavanaugh added In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels Sep 7, 2017
@chancancode
Copy link
Contributor

Just wanted to point out that this generally works without errors with the "No implicit returns" flag:

class Foo {
  maybeReturn(): string | void {
    if (Math.random() > 0.5) {
      return 'hello';
    }
  }
}

Playground link

@mhegazy mhegazy added Help Wanted You can do this and removed In Discussion Not yet reached consensus labels Sep 19, 2017
@mhegazy
Copy link
Contributor

mhegazy commented Sep 19, 2017

PRs welcome

@mhegazy mhegazy added this to the Community milestone Jan 4, 2018
@RyanCavanaugh RyanCavanaugh modified the milestones: Community, Backlog Mar 7, 2019
@bcherny
Copy link

bcherny commented Dec 23, 2019

Related bug in v3.7.2. noImplicitReturns doesn't affect the behavior.

// Error TS2366: Function lacks ending return statement and return
// type does not include 'undefined'.
function f(x: number): number {
  if (typeof x === 'number') {
    return 1
  }
}

Playground Link

Notably, this prevents you from expressing React props as unions:

import * as React from 'react'

type Props =
   | { a: number }
   | { b: string }

// Error TS2366: Function lacks ending return statement and return
// type does not include 'undefined'.
function MyComponent(props: Props): JSX.Element {
  if ('a' in props) {
    return <div>a is {props.a}</div>
  }
  if ('b' in props) {
    return <div>b is {props.b}</div>
  }
}

Playground Link

For this example to type check, we need to add a catch-all return statement at the end of MyComponent's body, which is not actually needed since at that point, props has already been refined to never.

@matthieusieben
Copy link

matthieusieben commented Jun 4, 2020

Not sure if related to this but I get the same behavior when returning void:

const aa = (a: any) => { // No error
  if (a) return
}

const bb = (b: any) => { // Not all code paths return a value.
  if (b) return void console.log("foo")
}

return void should be considered as a path that does not return a value, right?

@wycats
Copy link
Author

wycats commented Aug 18, 2020

@mhegazy since some time has gone by: is this still "PRs welcome"?

@rohitkhurmi095
Copy link

compilerOptions:{
"noImplicitReturns": false
}

@Mahi
Copy link

Mahi commented Apr 8, 2022

I'm not really sure if this error is "unexpected" or not. It's controlled by the "No implicit returns" flag and this is definitely an implicit return.

How is a void function not returning anything an implicit return? How come it works when using return-type annotation? This is definitely a bug. I don't want to hide all implicit return warnings, I just wish to hide those with an optional void as return type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

8 participants