-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Inference doesn't work with union types #2264
Comments
Maybe you could explain to me what exactly is a "complete mess and failure" here. I'm not seeing any errors getting reported in the Playground. |
short answer: slightly longer answer can be illustrated with this example: interface A { 'i am A': A }
interface B { 'i am B': B }
interface C { 'i am C': C }
type X = A | B | C;
var x = Math.random() > 0.33 ? <A> undefined : (Math.random() > 0.5 ? <B> undefined : <C> undefined);
function destructure<a, b, c, r>(x: a | b | c, haveA: (value: a) => r, haveB: (value: b) => r, haveC: (value: c) => r) : r {
/* here comes code smart enough to do destructuring */
return undefined;
}
var who_am_i = destructure(x, a => 'a', b => 'b', c => 'c'); // <-- why is everything {}? |
I agree that in the last example there is no clue on how to match the formal and actual type parameters other than by the order of declaration. However in the first example it's sort of obvious. |
More to that, if functions of the following sort don't make any sense in TS (due to not being able to match formal and actual type parameters) why are they allowed?
|
See issue #360 You can overcome the other shortcomings you've encountered by simply adding a type annotation to each function you pass in. interface A { 'i am A': A }
interface B { 'i am B': B }
interface C { 'i am C': C }
type X = A | B | C;
var x = Math.random() > 0.33 ? <A> undefined : (Math.random() > 0.5 ? <B> undefined : <C> undefined);
function dispatch<a, b, c, r>(x: a | b | c, haveA: (value: a) => r, haveB: (value: b) => r, haveC: (value: c) => r) : r {
/* here comes code smart enough to dispatch */
return undefined;
}
// Nothing is {}!
var who_am_i = dispatch(x,
(a: A) => 'a',
(b: B) => 'b',
(c: C) => 'c'); |
When inferring to a union type, type inference first attempts to infer to non-naked type parameters in the target. Failing that, if the union type contains a single naked type parameter, an inference is made to that type parameter. So, in your original example, we infer The type inference process never attempts to "carve up" a union type in discrete pieces. Because of structural typing it would be very hard to do so in a consistent and predictable manner. For example, what if When inferring to a type that is a union of two or more naked type parameters, there are simply no reasonable or consistent inferences to make--so we make none. For example: function foo<T, U>(x: T | U, f1: (value: T) => void, f2: (value: U) => void) { }
var v1: string | number;
var v2: number | string;
var v3: boolean | string | number;
foo(v1, x => {}, y => {});
foo(v2, x => {}, y => {});
foo(v3, x => {}, y => {}); There's just no meaningful way we could tease out consistent inferences for T and U in the above example. |
can we say no in this situation? this case looks like a completely valid no-goer because out of all knowledge that we have we cannot conclude a right answer, but this case is in the minority of all other ones accounting for the rest 97.8% percent where the inference can be done no problem I am not sure if that sounds like a proposal. I just wish problems were addressed not like all-or-nothing, but rather like we-do-what-we-can principle. |
Now fixed by #5738. |
@ahejlsberg Would it be possible to "carve up" a union type as you say, if all members of the union had a discriminant field? E.g. in the following example:
It almost works, in that the two |
I don't understand what is wrong with the following piece of code. It's a very basic scenario that I wish I could have since now union types are here. Please let me know what I am doing wrong:
At playground: http://www.typescriptlang.org/Playground#src=interface%20Y%20%7B%20'i%20am%20a%20very%20certain%20type'%3A%20Y%20%7D%0Avar%20y%20%3A%20Y%20%3D%20%3CY%3E%20undefined%3B%0Afunction%20destructure%3Ca%2C%20r%3E(%0A%09something%3A%20a%20%7C%20Y%2C%0A%09haveValue%3A%20(value%3A%20a)%20%3D%3E%20r%2C%0A%09haveY%3A%20(value%3A%20Y)%20%3D%3E%20r%0A)%20%3A%20r%20%7B%0A%09return%20something%20%3D%3D%3D%20y%20%3F%20haveY(y)%20%3A%20haveValue(%3Ca%3E%20something)%3B%0A%7D%0A%0Avar%20value%20%3D%20Math.random()%20%3E%200.5%20%3F%20'hey!'%20%3A%20%3CY%3E%20undefined%3B%0A%0Aconsole.log(destructure(value%2C%20text%20%3D%3E%20'string'%2C%20b%20%3D%3E%20'other%20one'))%3B%20%2F%2F%20%3C--%20complete%20mess%20and%20failure%0A
Related question at StackOverflow: http://stackoverflow.com/questions/28931221/whats-the-use-of-union-types-in-typescript
The text was updated successfully, but these errors were encountered: