ember-cli-typescript: TypeScript hangs with Promise.all(array) (With ArrayPrototypeExtensions)

Which package(s) does this problem pertain to?

What are instructions we can follow to reproduce the issue?

A small repo demonstrating a slow-down combining Promise.all while having interface Array<T> extends Ember.ArrayPrototypeExtensions<T> {}. Created it with as few moving parts as possible, so there is basically no code nor an ember app.

git clone git@github.com:mogstad/typescript-ember-slow-example.git
cd typescript-ember-slow-example
npm install
npm start

Now about that bug. What did you expect to see?

I expected the TypeScript code to be compiled swiftly.

What happened instead?

Running it on TS 3.0.3 takes 45 seconds, and 3.1.1 takes 8 minutes. We’re only seeing this issue using @types/ember >= 3.

Workarounds

We’ve found a few workarounds, by either defining the generic type of Promise.all<T> (and its friends). (Same issue if using rsvp)

let items = await Promise.all<string>(promises);

Or only extending MutableArray<T> instead of ArrayPrototypeExtensions, we’re not using anything in the Observable interface.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 23 (16 by maintainers)

Most upvoted comments

Trying to spend a bit of time digging into this today. Will report what I find!

On my to-do list for most likely next week to get a solid repro so I can help the TS team chase down the root of this regression.

Just keep deleting surrounding code until you get a reasonable build time and build back up - maybe try to see what array extensions trigger it. @sanders_n might know more.

@danielrosenwasser just raising this for your info; I’m going to try to have a minimal repro of some sort next week filed as a bug on the TS repo on both the basic compile time issues and the major 3.1 regression; any pointers as to the best way to get the info you all need for that would be 💯.

We worked around this in ember-osf-web (as @mogstad mentioned, but also including Copyable).

I did some playing around with this over the holiday break. It seems to be related to the conditional types in UnwrapComputedPropertyGetter. It does not seem to be the infer (I took it out and same result) but when I change the conditionals to hard-coded types, it compiles fast.

Default types:

$ time tsc

real    0m44.633s

Remove infer (e.g. hard-code string instead of inferred generic U):

$ time tsc

real    0m46.230s

Remove conditional (e.g. type UnwrapComputedPropertyGetter<T> = string;):

$ time tsc

real    0m3.670s

I also found that compile time is dependent on the number of usages of UnwrapComputedPropertyGetter. If I start removing usages in @types/ember__object/observable.d.ts:

Remove get:

$ time tsc

real    0m23.995s

Also remove getWithDefault:

$ time tsc

real    0m9.545s

Also remove cacheFor:

$ time tsc

real    0m3.977s

Interestingly, removing getProperties (which uses UnwrapComputedPropertyGetters, which uses UnwrapComputedPropertyGetter) had very little affect on compile time:

Remove getProperties:

$ time tsc

real    0m42.193s

Same here. Would label this as a bug, as it makes development unbearable.

Commenting out the line interface Array<T> extends Ember.ArrayPrototypeExtensions<T> {} in types/package-name/index.d.ts “fixes” the problem, though it leads to other problems obviously…

Ok, this is bizarre! Apparently, order matters. I’ll explain.

For https://github.com/mogstad/typescript-ember-slow-example

Using tsc 3.2.4, I get:

$ time npx tsc

real    9m57.583s

If I go into node_modules/@types/ember__object/observable.d.ts and move the definitions for getProperties and setProperties (that use the mapped types UnwrapComputedPropertyGetters and UnwrapComputedPropertySetters) to be the last things in the interface (so that they are defined after everything that uses UnwrapComputedPropertyGetter and UnwrapComputedPropertySetter), I get:

$ time npx tsc

real    0m53.262s

I discovered this accidentally while creating a minimal repro (which I’ll post shortly).