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
Expression produces a union type that is too complex to represent #33130
src/template-language-service-decorator.ts:44:13 - error TS2590: Expression produces a union type that is too complex to represent.
44 intercept[name] = wrapper(languageService[name]!.bind(languageService));
~~~~~~~~~~~~~~~
The code likely needs to be rewritten here but I'm opening this issue to make sure the error is expected
Righto, so name is a union of the 52 (! that API is big) keys in the language service object, while intercept is a Partial<LanguageService>, which means every property is a union of it's actual type (often a signature-containing object) and undefined. When we're assigning to this, we produce an intersection like - ((() => void) | undefined) & (((fileName: string) => DiagnosticWithLocation[]) | undefined) & (((fileName: string) => Diagnostic[]) | undefined) and so on, which we then normalize (so we distribute to lift the union to the outside). This normalization spreads the types, so you get something like (() => void) & undefined & undefined | (() => void) & ((fileName: string) => DiagnosticWithLocation[]) & undefined | (() => void) & ((fileName: string) => DiagnosticWithLocation[]) & ((fileName: string) => Diagnostic[]) and so on, enumerating every possible combination of the input types. Without any kind of simplification taken into account, for an intersection of 52 unions of 2 elements, we would need to produce 4.5e15 resulting top-level union elements. That's way too many. We calculate that number in advance, see that it's greater than our cap of 100000, and issue the error in the OP.
Now, this specific case, when we're distributing a ton of unions, all of which contain undefined, I think we could preemptively simplify to greatly reduce that number, since undefined can't be subtyped under our current rules (undefined intersected with pretty much anything else is always never). I posited as much when we originally added the limit, and it looks like we do have reason to do so. It's probably worth noting that what I'm thinking of'll only help situations where every input is a union containing undefined (and maybe null), though. :S
Reacted by AnyhowStep, John Nistico, DemoorBug, Mykyta Matushyn, Viet Ta, Kostayne, Abhishek Sharma and Gustavo Henke
Because the type simplifies massively upon construction - undefined and null, intersected with anything, are just never, so for every combination we made, we'd just get never, then discard that element and move on (which'd chew thru compute time but not really memory). Or that's what we would have done, had we been making the type prior to 3.5 - prior to 3.5 we were just not making the constraint correctly and unsoundly checked against a union of unions, so it never came up.
Activity
sandersn commentedon Aug 29, 2019
This error was added intentionally, so it’s likely to be by design, but we should take a look at the code to confirm.
weswigham commentedon Aug 29, 2019
Righto, so
nameis a union of the 52 (! that API is big) keys in the language service object, whileinterceptis aPartial<LanguageService>, which means every property is a union of it's actual type (often a signature-containing object) andundefined. When we're assigning to this, we produce an intersection like -((() => void) | undefined) & (((fileName: string) => DiagnosticWithLocation[]) | undefined) & (((fileName: string) => Diagnostic[]) | undefined)and so on, which we then normalize (so we distribute to lift the union to the outside). This normalization spreads the types, so you get something like(() => void) & undefined & undefined | (() => void) & ((fileName: string) => DiagnosticWithLocation[]) & undefined | (() => void) & ((fileName: string) => DiagnosticWithLocation[]) & ((fileName: string) => Diagnostic[])and so on, enumerating every possible combination of the input types. Without any kind of simplification taken into account, for an intersection of 52 unions of 2 elements, we would need to produce 4.5e15 resulting top-level union elements. That's way too many. We calculate that number in advance, see that it's greater than our cap of 100000, and issue the error in the OP.Now, this specific case, when we're distributing a ton of unions, all of which contain
undefined, I think we could preemptively simplify to greatly reduce that number, sinceundefinedcan't be subtyped under our current rules (undefinedintersected with pretty much anything else is alwaysnever). I posited as much when we originally added the limit, and it looks like we do have reason to do so. It's probably worth noting that what I'm thinking of'll only help situations where every input is a union containingundefined(and maybenull), though. :Sfatcerberus commentedon Aug 30, 2019
My question: if normalization was really producing that many types, why did this work before instead of, you know, causing OoM?
weswigham commentedon Aug 30, 2019
Because the type simplifies massively upon construction -
undefinedandnull, intersected with anything, are justnever, so for every combination we made, we'd just getnever, then discard that element and move on (which'd chew thru compute time but not really memory). Or that's what we would have done, had we been making the type prior to 3.5 - prior to 3.5 we were just not making the constraint correctly and unsoundly checked against a union of unions, so it never came up.