You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Type argument incorrectly inferred from union typeΒ #56792
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.
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.
exportinterfaceReader<R,A>{(r: R): A;}declareconstchain: <A,R,B>(f: (a: A)=>Reader<R,B>)=>(ma: Reader<R,A>)=>Reader<R,B>;declareconstboolean: boolean;declareconsta: Reader<string,number>;declareconstb: 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
interfaceLeft<E>{readonly_tag: "Left";readonlyleft: E;}interfaceRight<A>{readonly_tag: "Right";readonlyright: A;}exporttypeEither<E,A>=Left<E>|Right<A>;declareconstchain: <E,A,B>(f: (a: A)=>Either<E,B>)=>(ma: Either<E,A>)=>Either<E,B>;declareconstboolean: boolean;declareconsta: Either<string,string>;declareconstb: 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, G<T | U> cannot be safely substituted for G<T> | G<U> for arbitrary G, so TS wonβt even attempt inferences that imply such a substitution.
Argument of type '[string] | [number]' is not assignable to parameter of type '[string]'.
i.e. TS infers A = string for the call to f and subsequently produces an error upon trying to pass a [string] | [number] (that is, x) to a parameter typed as [A] = [string]. So the description of actual behavior looks correct to me.
That is a workaround if the function declaration can be modified (or the function declaration could be coerced). Is there any semantic difference between
declare const f: <A>(t: [A]) => void;
and
declare const f: <A extends [unknown]>(t: A) => void;
? 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?)
Activity
Andarist commentedon Dec 15, 2023
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.
jcalz commentedon Dec 15, 2023
If it's a feature request then it duplicates #44312
(also see #19596 and SO question)
OliverJAsh commentedon Dec 15, 2023
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.
and
fatcerberus commentedon Dec 16, 2023
Thereβs also the fact to consider that, in general,
G<T | U>cannot be safely substituted forG<T> | G<U>for arbitraryG, so TS wonβt even attempt inferences that imply such a substitution.fatcerberus commentedon Dec 17, 2023
Craig P Hicks (@craigphicks) The OP claims that Actual Behavior is:
which is consistent with the error message:
i.e. TS infers
A = stringfor the call tofand subsequently produces an error upon trying to pass a[string] | [number](that is,x) to a parameter typed as[A] = [string]. So the description of actual behavior looks correct to me.craigphicks commentedon Dec 17, 2023
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.
typescript-bot commentedon Dec 23, 2023
This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.