Repository navigation
Adding parentheses changes the result of type inference #56270
Description
Activity
Andarist commented
on Oct 31, 2023 ContributorMore actionsThe original PR that made the non-parenthesized version to work can be found here: #52091
Reacted by MaxThis is working as intended, though I agree it is a bit surprising. We gramatically check for conditional types of the pattern
[X] extends [Y] ? ...(where[X]and[Y]are tuple types of the same arity) and defer their resolution if some of theXorYelements are generic. This is such that non-distributable conditional types can be written[X] extends [Y] ? ...and be deferred similarly toX extends Y ? .... We document this behavior here.We specifically don't first erase parentheses because that is just one of untold number of ways you could write a type that turns out to be a tuple type. The tuple types are in a sense immaterial (when they match on both sides they are effectively erased), but we want the explicit matching brackets on both sides to be the signal that this type is non-distributive.
- addedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
on Oct 31, 2023 Won't this mean that running a formatter which removes or adds parens will change behavior?
Andarist commented
on Oct 31, 2023 ContributorMore actionsIt does mean that - it happened to me just today when I was playing with this ;p
I feel like unwrapping parens is a good idea exactly for that reason. Formatters frequently unparen or reparen expressions depending on their position and complexity. They won't add or remove other syntax, though, so I don't think we're breaking into the realm of the other ways to make a tuple type by handling it.
defer their resolution if some of the
XorYelements are generic ...export type AddWithInfer<A extends number, B extends number> = [ IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>, IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>, ] extends infer R extends [boolean, boolean, boolean, boolean] ? [true, false] extends (infer _ extends ([R[0], R[3]])) // Note: with infer ? PositiveInfinity : 'failed' : never; type AddTest2 = AddWithInfer<PositiveInfinity, PositiveInfinity>; // Infinity, works too!
Anders Hejlsberg (@ahejlsberg) So using "infer" makes it work, because "infer" leads to something like that(
defer their resolution), right? 😃- removedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
on Nov 1, 2023 - locked as resolved and limited conversation to collaborators
on Oct 22, 2025
🔎 Search Terms
"constraint evaluation", "type infer"
🕗 Version & Regression Information
In Version 5.x, parentheses changes the result of type inference;
In Version 4.9 - 4.7(The minimum version that supports
infer X extends ...), parentheses not changes the result of type inference;⏯ Playground Link
playground link
💻 Code
🙁 Actual behavior
🙂 Expected behavior
Additional information about the issue
see also: #51090