ember-cli-typescript: [@types/ember bug] - ember types are broken in TypeScript 3.1

Which package(s) does this problem pertain to?

What are instructions we can follow to reproduce the issue?

npm install -g typescript@latest
tsc -v      # make sure it's a v3.x (i.e. Version 3.1.0-dev.20180810)
git clone https://github.com/DefinitelyTyped/DefinitelyTyped
cd DefinitelyTyped
npm install
cd types/ember
tsc

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

I expected tsc to compile the ambient types and test files successfully

What happened instead?

test/array-ext.ts:16:32 - error TS2345: Argument of type 'ComputedProperty<Fix<Person & { name: string; }> | undefined, Fix<Person & { name: string; }> | undefined>'is not assignable to parameter of type 'Person'.
  Property 'name' is missing in type 'ComputedProperty<Fix<Person & { name: string; }> | undefined, Fix<Person & { name: string; }> | undefined>'.

16 assertType<Person | undefined>(array.get('firstObject'));

NOTE

Switching to a TypeScript 2.x

npm install -g typescript@2
tsc

will compile the tests successfully and without error.

About this issue

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

Most upvoted comments

Fix for a variety of ember types has been merged

Ah, yes, the generic types need to be used somewhere. Otherwise a ComputedProperty<foo> is structurally identical to a ComputedProperty<bar>. I’m surprised it ever worked.

I ran into an interesting situation where it looks like TypeScript may be discarding some information.

Currently our Ember.ComputedProperty type makes no use of the generics it receives. I’m guessing that the original intent was to sort of “tag” the CPs with information that can be extracted later.

If we simplify this to the typical Boxed type

// kind of like our Ember.ComputedProperty
type Box<T, U = T> = { value: any };
// a ComputedProperty<string> that's clobbered with a string via .extend() or .create()
type MaybeBoxed<T> = Box<T> & T;

// kind of like @dwickern's approach to getting the value type from
//   something that **might** be a CP (or might not)
type UnBox<S> = S extends Box<infer T> ? T : S;

// a concrete example for us to think about
type MaybeBoxedString = Box<string> & string;

type Unboxed = UnBox<MaybeBoxedString>; // {} 🚨  -- would be nice if it were a string!

This problem seems to be solved by using any generic anywhere

type Box<T, U = T> = { value: any, __do_not_touch_this: T };
type MaybeBoxed<T> = Box<T> & T;

type UnBox<S> = S extends Box<infer T> ? T : S;

type MaybeBoxedString = Box<string> & string;

type Unboxed = UnBox<MaybeBoxedString>; // string ✅

Thankfully the type in question is a class, so we can use a private field for this and no harm is done