Skip to content

Exponential compilation slowdown with property accessors and conditional types #29350

Open
@alexfoxgill

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

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions