-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Type argument incorrectly inferred from union type #56792
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
The difference is that in those other examples the type parameter appears in what it considers a naked~ position. It unionify candidates from such positions. The union of tuples is different since the position is not naked, itβs an element inside a tuple type. This isnβt incorrect. How different inferences work is often just heuristic-based. As far as I know, this is working as intended - itβs not a bug. It can be treated as a feature request though. |
If it's a feature request then it duplicates #44312 (also see #19596 and SO question) |
Thanks for the responses. If it provides more context, below is the original real world problem I encountered before reducing it down to the examples you see above. I've extracted these types from the popular library fp-ts. export interface Reader<R, A> {
(r: R): A;
}
declare const chain: <A, R, B>(
f: (a: A) => Reader<R, B>
) => (ma: Reader<R, A>) => Reader<R, B>;
declare const boolean: boolean;
declare const a: Reader<string, number>;
declare const b: Reader<number, number>;
// Type argument `R` inferred as `string`.
// Ideally this would be `string | number`.
chain(() =>
// Error: Type 'string' is not assignable to type 'number'.
boolean ? a : b
); and interface Left<E> {
readonly _tag: "Left";
readonly left: E;
}
interface Right<A> {
readonly _tag: "Right";
readonly right: A;
}
export type Either<E, A> = Left<E> | Right<A>;
declare const chain: <E, A, B>(
f: (a: A) => Either<E, B>
) => (ma: Either<E, A>) => Either<E, B>;
declare const boolean: boolean;
declare const a: Either<string, string>;
declare const b: Either<string, number>;
// Type argument `B` inferred as `string`.
// Ideally this would be `string | number`.
chain(() =>
// Error: Type 'number' is not assignable to type 'string'.
boolean ? a : b
); |
Thereβs also the fact to consider that, in general, |
@craigphicks The OP claims that Actual Behavior is:
which is consistent with the error message:
i.e. TS infers |
The definition can be modified to make it pass without inferring a union, while still requiring the argument to be a unary-tuple.
That is a workaround if the function declaration can be modified (or the function declaration could be coerced). Is there any semantic difference between
and
? If no semantic difference, then it could be argued that they should infer in exactly the same way, and that therefore this issue is a bug, even if it is a design bug. (Maybe there are some other test cases that former passes that the latter doesn't?) Here is another example of what seem to be semantically identical generics where one has trouble. |
This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
π Search Terms
π Version & Regression Information
β― Playground Link
https://www.typescriptlang.org/play?#code/CYUwxgNghgTiAEYD2A7AzgF3gMwFzwB4BBAPgAoN8BtIgXQEp4BeE+ANyQEtgBuAKFCRYCZOiwAPaphicUAc1rwAPvCooArgFsARiBi1+fbGXH0eQA
π» Code
π Actual behavior
TypeScript infers the type argument as
string
.π Expected behavior
TypeScript infers the type argument as
string | number
.Additional information about the issue
This issue appears to describe a similar problem with functions: #52295.
Reduced test case:
The text was updated successfully, but these errors were encountered: