Skip to content

Type predicated should eliminate execution path #32648

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

Closed
ycmjason opened this issue Aug 1, 2019 · 6 comments
Closed

Type predicated should eliminate execution path #32648

ycmjason opened this issue Aug 1, 2019 · 6 comments

Comments

@ycmjason
Copy link

ycmjason commented Aug 1, 2019

TypeScript Version: 3.5.1

Search Terms:

  • type predicate
  • path
  • eliminate

Code

type Awesome = 'i' | 'am' | 'awesome'

const isActuallyAwesome = (x: Awesome): x is 'awesome' => x === 'awesome'

const isNotReallyAwesome = (x: Awesome): x is 'i' | 'am' => x !== 'awesome'


const happyFunction = (a: Awesome): number => {
    if (isActuallyAwesome(a)) {
        return 0
    }

    if (isNotReallyAwesome(a)) {
        // typescript not be able to infer `isNotReallyAwesome(a)` always evaluates to true at this point?
        return 1
    }

    throw 'i need to throw :('
}

Expected behavior:
isNotReallyAwesome has type signature: (x: Awesome) => x is 'i' | 'am'. Shouldn't TS be able to tell when x is passed in as 'i' | 'am' and therefore infer that it will always return true?

I hope this make sense.

Actual behavior:

Playground Link:

https://www.typescriptlang.org/play/index.html#code/C4TwDgpgBAgg7hAzgewLbQLxQOQEttQA+OAhqgcdiQiutgFD0DGyAdosFLojE8AK4kANkJDwkaTFAAUADwBcsGpICUi2V0SlldKBgB8UDRhPaJdRi3aduAOWTAAShGGjxtKXMXvV6zTnwiUnI9Qw0AQlMqHQgGSzYOKAALEjAwEAAxflY+XDY9GRJvGLUoVn5UACMIACdQqABveigWrgAzGW5eAVcxGOkSFRVG5taxmogBGtYoAAZRloBfRjHcDuk7B2den3QBoZGxsYB6Y6gWfiEAEyhQSEQmGtwwTmqoEkqhaGBkLlY22qaexOFwiPrmCD7d5COAkEBaCAAN2EgmASFuv2ANX40BInGASW4UDAyFwrGAAH4FkcJlMZgBGanLakEmrIOABMoQCA3H63JJsjnyaQMZlAA

@jack-williams
Copy link
Collaborator

jack-williams commented Aug 1, 2019

TypeScript does infer that the conditional is always true.

const happyFunction = (a: Awesome): number => {
    if (isActuallyAwesome(a)) {
        return 0
    }

    if (isNotReallyAwesome(a)) {
        return 1
    }

    const whenAmIReachable: never = a
    return a;
}

But if you're looking for actual code elimination in the compiled output - that's never going to happen as per:

This could be implemented without emitting different JS based on the types of the expressions

@ycmjason ycmjason closed this as completed Aug 1, 2019
@ycmjason ycmjason reopened this Aug 1, 2019
@ycmjason
Copy link
Author

ycmjason commented Aug 1, 2019

i didn't mean code elimination in the compiled code.

I mean that typescript should be able to infer that whatever after the second conditional is dead code.

I should not need to write throw 'i need to throw :('

@ycmjason
Copy link
Author

ycmjason commented Aug 1, 2019

Let me give another example:

const coolFunction = (): number => {
    if (true) {
         return 1
    } 

     // typescript won't complain about the return type should be `number | undefined`
}

so shouldn't the my example have the same behaviour?

@jack-williams
Copy link
Collaborator

This issue explains why the literal true is treated differently: #29323.

@jack-williams
Copy link
Collaborator

Also covered here: #17358.

@ycmjason
Copy link
Author

ycmjason commented Aug 1, 2019

thanks @jack-williams !

@ycmjason ycmjason closed this as completed Aug 1, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants