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

if/typeof/in type narrowing on union type's uncommon properties #5816

Closed
massimonewsuk opened this issue Feb 14, 2018 · 9 comments
Closed

if/typeof/in type narrowing on union type's uncommon properties #5816

massimonewsuk opened this issue Feb 14, 2018 · 9 comments

Comments

@massimonewsuk
Copy link

Code

interface Bird {
    fly: () => any;
    layEggs: () => any;
}

interface Fish {
    swim: () => any;
    layEggs: () => any;
}

function Move(pet: Fish | Bird) {
    if (pet.swim) {
        pet.swim();
    } else {
        pet.fly();
    }
    
    if (typeof pet.swim === "function") {
        pet.swim(); // Only this line works
    } else {
        pet.fly();
    }

    if ("swim" in pet) {
        pet.swim();
    } else {
        pet.fly();
    }
}

Expected behavior:
I expect the code above to work without any errors at all. I feel it's all reasonable.

Actual behavior:
I get error for all if/else branches. The only place that works is commented above.

@massimonewsuk
Copy link
Author

Still an issue in v0.67.0

@TrySound
Copy link
Contributor

TrySound commented Mar 7, 2018

post code also in flow.org/try please

@massimonewsuk
Copy link
Author

Still an issue in v0.70.0

@vkurchatkin
Copy link
Contributor

Not a bug. pet.swim doesn't prove that it is a Fish, it could be a Bird with swim property of an arbitrary type.

@massimonewsuk
Copy link
Author

@vkurchatkin Have a look at the following example which uses "exact" types instead (so Bird shouldn't have the swim property of an arbitrary type)...

type Bird = {|
    fly: () => any;
    layEggs: () => any;
|}

type Fish = {|
    swim: () => any;
    layEggs: () => any;
|}

function Move(pet: Fish | Bird) {
    if (pet.swim) {
        pet.swim(); // Works fine
    } else {
        pet.fly(); // Works fine
    }
    
    if (typeof pet.swim === "function") {
        pet.swim(); // Only this line works
    } else {
        pet.fly(); // Doesn't work - thinks pet could be a fish
    }

    if ("swim" in pet) {
        pet.swim(); // Doesn't work - thinks pet could be a bird
    } else {
        pet.fly(); // Doesn't work - thinks pet could be a fish
    }
}

@vkurchatkin
Copy link
Contributor

Yes, this makes sense for exact object, but there is an issue for that already

@massimonewsuk
Copy link
Author

@vkurchatkin Are you referring to this one? #4772

@vkurchatkin
Copy link
Contributor

Yes, but I think there are others

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

3 participants