-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Flow does not accept intersection function types even with disjoint unions #3021
Comments
bump |
I don't think this is a bug. The program in the original post asks whether the following subtyping rule is true:
The above is not true, but the reverse is true. |
I agree that the subtyping relation you wrote is not true, but I think the spirit of the bug is that there's no way to write |
Yeah, the feature request here is to get flow to accept a real javascript function as an intersection of function types. You can declare function intersections and you can cheat by first casting a function to const foo: F = (ab) => {
if (ab.type === 'a') {
return ab.a;
} else {
return ab.b;
}
} |
I noticed something interesting recently: // @flow
interface T {
(t: number): number;
(t: string): string;
}
declare var returnTypeInterface: T;
(returnTypeInterface('string'): string);
(returnTypeInterface(2): number);
// $ExpectError
(returnTypeInterface('string'): number);
// $ExpectError
(returnTypeInterface(2): string); (Flow Try) This seems to work. But I'm not sure if it's safe. |
@samwgoldman @mrkev can we reopen this issue? |
I think an issue I'm having is related to this, so I'm asking about it here: I'm trying to get a function to return different, but related, types based on the type of the input. For example: type Arg = { +[string]: Object }
type CallbackArg = () => Arg
type Func = <T: Arg | CallbackArg>(T) => /* Here's where I'm stuck. */ What I'd like to do is return For clarification, by the way, I'm dealing with this inside a type declaration file, so I can't write some kind of utility function to handle the conditional for me via I was able to get it mostly working via type Func = <T: Arg | CallbackArg>(T) => { +[$Keys<T> | $Keys<$Call<T>>]: string } but it seems kind of awkward. I'm also not sure why this would work, as I would think Flow would complain about (Try) |
An interface is probably your best bet: Try |
Huh. That should probably be in the documentation. Oddly, the order seems to affect it. If the variant that takes Edit: And I've just noticed that @zeorin was talking about the same thing. Totally didn't notice because I didn't even think that an interface would have anything to do with this particular problem. Woops. |
Interesting question! An interface is probably cleanest, I didn't realise they work that way either... good to know. I think it essentially desugars to an intersection type; this (try) is what I came up with when experimenting. The relevant bit being: type ObjectToString = Object => string;
type Func =
& (<T: Arg>(() => T) => $ObjMap<T, ObjectToString>)
& (<T: Arg>(T) => $ObjMap<T, ObjectToString>); @DeedleFake wrt order, I believe they're tried left-to-right (or top-down in the case of multiple declarations in an interface I suppose), so you probably want to put more specific types first. |
I've also been using intersection function types for this recently. I wish the docs mentioned this behaviour. I figure an intersection object type is really used to check whether something is more than one (inexact) object type at the same time. So for an intersection function type, it's really more than one function type at the same time. Of course, in my own code that's usually a good sign I'll be better off just creating individual functions instead, but sometimes I have to type other people's code, Redux + Redux Thunk's dispatch being a good example. |
Hi!
I have the following code (try link)
I wish to make a function
foo
accepting a disjoint union but which returns different types for each member.This fails with the following error:
What's the best way to express this type of function (disjoint types input, but different output type for each one)? I would like to not have to declare it as
(ab: A|B) => string|number
because that loses some information.Sincerely,
Dan
The text was updated successfully, but these errors were encountered: