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
Inference from rest parameters has strange inconsistent results #37193
Since this isn't assignable we pick the constraint over the inferred type.
It's not easy to change this inferred constraint to readonly unknown[] (nor to readonly unknown[] | unknown[]) since people might pass this infer type parameter to other types in places where any[]/unknown[] is expected. I find it usually better to use readonly unknown[] over unknown[] for my constraints - it's better since usually I was to allow both mutable and readonly arrays. However, not everybody does that (and I'm often lazy too, and don't include the readonly modifier ;p). So changing that would likely break a lot of types.
Alternatively, getInferredType could have some heuristics to ignore the inferred constraint but I don't know what that would look like exactly. I experimented with a couple of things and actually got some promising results for this. A couple of branches in getInferredTypeParameterConstraint are just matching things syntactically. Maybe there is a difference between a constraint that has to be used for substitution types and the one that has to be tested against in getInferredType?
Note that I would consider those to have a semantic and not a syntactic match (and this case is also inferrable through getInferredTypeParameterConstraint):
I'm one year more experienced now 😉 and I don't see how this can be fixed without breaking something.
The problem is that the implied constraint of those rest params is unknown[] so naturally an inferred result of readonly any[] doesn't satisfy it. On such an occasion the constraint is picked as the inferred type. This results in an unexpected behavior for the user.
What can be done about it? I see 2 possible solutions.
change the implied constraint for rest params to readonly unknown[]. This would allow both mutable and readonly arrays. It sounds good, right? The problem is that now this code would fail:
typeAcceptArr<Textendsunknown[]>=TtypeA<T>=Textends(...rest: infer P)=>any ? AcceptArr<P> : never
allow readonly arrays to satisfy this constraint check (by introducing a special internal type). This would result in problems at instantiation time because the type parameter's constraint within the conditional type would still be unknown[] but yet then that type could be instantiated with a type that doesn't satisfy that constraint
I think only option 1 is viable here but it's a breaking change.
Activity
5 remaining items
Andarist commentedon Mar 6, 2023
This might be a hard thing to fix unless you would be OK with some breakage. The problem is in the
getInferredTypeParameterConstraint:https://github.dev/microsoft/TypeScript/blob/43cc362cef72e5fa1372f59736a9c4b55d85def0/src/compiler/checker.ts#L14949-L14955
Because of this we end up checking if
readonly number[]is assignable tounknown[]in thegetInferredType:https://github.dev/microsoft/TypeScript/blob/43cc362cef72e5fa1372f59736a9c4b55d85def0/src/compiler/checker.ts#L25022-L25028
Since this isn't assignable we pick the constraint over the inferred type.
It's not easy to change this inferred constraint to
readonly unknown[](nor toreadonly unknown[] | unknown[]) since people might pass thisinfertype parameter to other types in places whereany[]/unknown[]is expected. I find it usually better to usereadonly unknown[]overunknown[]for my constraints - it's better since usually I was to allow both mutable and readonly arrays. However, not everybody does that (and I'm often lazy too, and don't include thereadonlymodifier ;p). So changing that would likely break a lot of types.Alternatively,
getInferredTypecould have some heuristics to ignore the inferred constraint but I don't know what that would look like exactly. I experimented with a couple of things and actually got some promising results for this. A couple of branches ingetInferredTypeParameterConstraintare just matching things syntactically. Maybe there is a difference between a constraint that has to be used for substitution types and the one that has to be tested against ingetInferredType?Note that I would consider those to have a semantic and not a syntactic match (and this case is also inferrable through
getInferredTypeParameterConstraint):Using this "prefer inferred type over inferred syntactical constraint" logic could also fix #46020 and #44143 (according to my local experiment).
Andarist commentedon Aug 14, 2024
I'm one year more experienced now 😉 and I don't see how this can be fixed without breaking something.
The problem is that the implied constraint of those rest params is
unknown[]so naturally an inferred result ofreadonly any[]doesn't satisfy it. On such an occasion the constraint is picked as the inferred type. This results in an unexpected behavior for the user.What can be done about it? I see 2 possible solutions.
readonly unknown[]. This would allow both mutable and readonly arrays. It sounds good, right? The problem is that now this code would fail:unknown[]but yet then that type could be instantiated with a type that doesn't satisfy that constraintI think only option 1 is viable here but it's a breaking change.
Andarist commentedon Aug 14, 2024
There is also an option number 3. Rest parameters could strip readonly-ness from instantiations. This would feel consistent with rests in tuples:
It would also be consistent with the proposed fix for #53398