Exponential compilation slowdown with property accessors and conditional types #29350
Description
Apologies, I have had to break from the template in order to describe this issue since it is not easily reproduced in a simple demo.
TypeScript Version: 3.0.3, 3.2.2, 3.3.0-dev.20190110
Search Terms: compilation performance, generic property accessor, conditional types
Code
So far in investigating this issue I have identified this code block as the culprit, due to this commit
export type PropOverloads<D extends Dimensionality, S extends Structure, A, B, Params extends {}> = {
<K1 extends keyof B>(key: K1)
: Composable.ComposeResult<A, B[K1], Params, D, Dimensionality.Single, S, Structure.Select>
<K1 extends keyof B, K2 extends keyof B[K1]>(k1: K1, k2: K2)
: Composable.ComposeResult<A, B[K1][K2], Params, D, Dimensionality.Single, S, Structure.Select>
<K1 extends keyof B, K2 extends keyof B[K1], K3 extends keyof B[K1][K2]>(k1: K1, k2: K2, k3: K3)
: Composable.ComposeResult<A, B[K1][K2][K3], Params, D, Dimensionality.Single, S, Structure.Select>
<K1 extends keyof B, K2 extends keyof B[K1], K3 extends keyof B[K1][K2], K4 extends keyof B[K1][K2][K3]>(k1: K1, k2: K2, k3: K3, k4: K4)
: Composable.ComposeResult<A, B[K1][K2][K3][K4], Params, D, Dimensionality.Single, S, Structure.Select>
}
"Supporting" code:
export enum Dimensionality {
Single = "single",
Maybe = "maybe"
}
export namespace Dimensionality {
export type Highest<T extends Dimensionality, U extends Dimensionality> =
Dimensionality extends T ? never
: Dimensionality extends U ? never
: Dimensionality.Maybe extends (T | U) ? Dimensionality.Maybe
: Dimensionality.Single extends (T | U) ? Dimensionality.Single
: never
}
export enum Structure {
Get = "get",
Select = "select",
Convert = "convert"
}
export namespace Structure {
export type Narrowest<T extends Structure, U extends Structure> =
Structure extends T ? never
: Structure extends U ? never
: Structure.Get extends (T | U) ? Structure.Get
: Structure.Select extends (T | U) ? Structure.Select
: Structure.Convert extends (T | U) ? Structure.Convert
: never
}
export type Composable<A, B, Params extends {}> =
| Get<A, B, Params>
| MaybeGet<A, B, Params>
| Selector<A, B, Params>
| MaybeSelector<A, B, Params>
| Converter<A, B, Params>
| MaybeConverter<A, B, Params>
export type ShapeResult<D1 extends Dimensionality, D2 extends Dimensionality, S1 extends Structure, S2 extends Structure> =
Shape<Dimensionality.Highest<D1, D2>, Structure.Narrowest<S1, S2>>
export type ComposeResult<A, B, P extends {}, D1 extends Dimensionality, D2 extends Dimensionality, S1 extends Structure, S2 extends Structure> =
Extract<Composable<A, B, P>, ShapeResult<D1, D2, S1, S2>>
Expected behavior: A compilation time of ~3 seconds, akin to the previous commit
Actual behavior: A compilation time of ~80 seconds
Related Issues: none that I could find
Output of tsc --diagnostics
Before this change, in the previous commit:
Symbols: 121139
Types: 67276
Memory used: 131777K
Check time: 2.36s
Total time: 3.19s
After this change:
Symbols: 1313985
Types: 788655
Memory used: 911104K
Check time: 78.97s
Total time: 79.67s
Without the 4-argument overload:
Symbols: 1085472
Types: 650274
Memory used: 763202K
Check time: 45.22s
Total time: 45.97s
With only the 1- and 2-argument overloads:
Symbols: 868055
Types: 522824
Memory used: 619599K
Check time: 27.51s
Total time: 28.21s
With only the 1-argument overload:
Symbols: 651404
Types: 399632
Memory used: 499634K
Check time: 16.01s
Total time: 16.68s
I am not really sure how to narrow this down to a particular problem or debug the compilation time; I only notice that the number of types and symbols increases hugely with just a single method interface