-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Variables type wrong unification / conditional inference #48714
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
Comments
Without going into the reasons for, or reasonableness of, the behavior you note - please notice the behavior when
As you can see it is tracking the return types as you probably expect. |
@craigphicks yes, this example only works because type Foo = { a: number; };
type Bar = { a: number; b: number }; |
The error you demonstrate can be resolved like this
The logic is that requiring explicit disambiguation prevents a mistaken assignment. |
I understand. But as mentioned earlier, the compiler can actually resolve this automatically to:
(see example with inline objects) E.g. I faced this issue with 2 endpoints in the library. With declaration like: declare const GetA: () => Promise<{ url: string; }>;
declare const GetB: () => Promise<{ url: string; shards: number; }>; Obviously, I don't control the objects shape here. |
This is not an incorrect inference. Shoehorning the optional members back in can happen in cases where it's straightforward for TS to detect that it's possible, but this is not guaranteed to occur in all cases. |
Ok. |
Type guards can make the code clearer
Alternatively you can add a discriminant
|
@HanabishiRecca - A fundamental observation - combining types with a logical-OR is an "obvious" approach, as you say. Adding types to a dictionary would be cheap. But as the number of types increase, (1) memory increases, and (2) type checking operations (which may be > O(dict size)) reading the dictionary becomes prohibitively expensive. The Typescript approach is a set of transformational rules that automatically "condense" the types, as the types are encountered, and the rules vary by situation. Unlike logical-OR, however, there are many conceivable approaches to "condensing" types. In fact the type operator There are loads of discussions on this topic of combining types, e.g., "Proposal: Add an "exclusive or" (^) operator #14094 ". Your case where you are faced with pre-existing types you can't or don't want to refactor - my prescriptive solution above of adding a fields (or wrapping in another type) is definitely heavy handed - it's against principle to add actual code for the sake of type checking when the types disappear in the actual JS output anyway. However, the type guards solution above doesn't scale when types are combined further, and to actually get the full value of type checking, adding actual coded properties seems like the best practical solution - I'd be happy to know better solutions - please instruct me when you find them. |
@craigphicks, well, I ended up explicitly declaring "merged" type. Something like: const result: {
a: number;
b?: number;
} = Math.random() > 0.5 ?
foo : bar; Not so convinient as inference, but works. |
Bug Report
π Search Terms
unification, variable type, conditional inference
π Version & Regression Information
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
result
type andresolve
return type inferred asfoo
only ({ a: number; }
).π Expected behavior
result
type andresolve
return type obviously should be inferred asfoo | bar
(in some form of{ a: number; }
and{ a: number; b: number; }
union).More info
This only happens when:
foo
andbar
share at least 1 property.Example with inline objects:
Here types are inferred as expected:
The text was updated successfully, but these errors were encountered: