I have two different unions of objects (versioned and unversioned objects), and for each one a creation result (object) type "UnversionedObjectCreation" and "VersionedObjectCreation". They use a generics parameter to limit each one to the versioned or unversioned object types respectively.
Since they are similar (the versioned one has two more properties, otherwise they are the same) I also have a union of those two object creation types. This one has two generics parameters "(U, V)", one is "forwarded" to the unversioned, one to the versioned component of the union.
This mostly works, except for when I try to use a union of object types as generics parameter instead of only a single one. Out of this problem I created a tiny piece of code (compared to the original) that already gets equally confused (and confusing).
What I'm trying to do is to tell Flow that a particular function returns an array of results of (for example) of objects UV1, V1 and V2. It works when I have two "*" generic parameters, or two single object types. But I want <UV1, V1 | V2>, what is the problem?
If you remove the return type union and instead of ResultType<V1 | V2> write ResultType<V1> it works. But I want v2Result in there too.
type V1 = {type: 'v1'};
type V2 = {type: 'v2'};
type MyUnion = V1 | V2;
type ResultType<T: MyUnion> = {|
obj: T,
objHash: string,
idHash: string
|};
function demo (
v1Result: ResultType<V1>,
v2Result: ResultType<V2>
): Array<ResultType<V1 | V2>> {
return [v1Result];
};
Error: src/main.js:4
4: type V1 = {type: 'v1'};
^^^^ string literal `v1`. Expected string literal `v2`, got `v1` instead
5: type V2 = {type: 'v2'};
^^^^ string literal `v2`
Error: src/main.js:5
5: type V2 = {type: 'v2'};
^^^^ string literal `v2`. Expected string literal `v1`, got `v2` instead
4: type V1 = {type: 'v1'};
^^^^ string literal `v1`
Found 2 errors
Even smaller, I can leave out the array and just use
function demo (
v1Result: ResultType<V1>,
v2Result: ResultType<V2>
): ResultType<V1 | V2> {
return v1Result;
};
This plain-type version has no errors.
function demo (
v1Result: V1,
v2Result: V2
): V1 | V2 {
return v1Result;
};
The above is the _very_ short version of what I really want to do. A slightly longer version with more verbose names that show the intended use:
So, for some type T<X> and unrelated types A and B, is T<A> a subtype of T<A|B>?
It depends on the polarity of X in T. In your example, it's neutral, so invariance holds: T<A> <: T<A|B> => A <: A|B && A|B <: A. The A|B <: A part is untrue, and is the type error here.
If X had a positive polarity in T, then covariance would hold: T<A> <: T<A|B> => A <: A|B, and A <: A|B is trivially true.
All of that is a long-winded, overly technical way of saying put a + on the type parameter to ResultType, like so.
Works — great. But I don't understand what you just wrote, and I think that's the problem with this type stuff: It is FAR more complicated than the code it is supposed to annotate. To me it's simple: A union is when I want to tell the type system that something could be any of those things, and that's how it usually works.
Is the general rule then that in order to use a union of types as a generics parameter I have to use the "+", and without it it has to be a single parameter only?
For any T<X>, T<A|B> can only be a shortcut for T<A>|T<B>. It's logically impossible to have T<X> that returns something from A|B that is neither T<A> nor T<B>. Prove me if I'm wrong.
Ever heard about math? Any constructive arguments?
@ElvenMonky Keep talking to yourself — but please do so at home, angry person. Get out of my (closed!) issue, please. It's closed for a reason, especially to people who have nothing interesting to add whatsoever.
Do you think that invoking a word ("Math"!!!), like magic, makes anything you say more useful? Do you believe in magic?
Then I'll say a few words too: "science", "reason",of and "math". There, now my comment is soo much better, right? Just like that. /s
Most helpful comment
@ElvenMonky Keep talking to yourself — but please do so at home, angry person. Get out of my (closed!) issue, please. It's closed for a reason, especially to people who have nothing interesting to add whatsoever.
Do you think that invoking a word ("Math"!!!), like magic, makes anything you say more useful? Do you believe in magic?
Then I'll say a few words too: "science", "reason",of and "math". There, now my comment is soo much better, right? Just like that. /s