diff --git a/.eslintrc.js b/.eslintrc.js
index ea485051c..c9e89f0bf 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -7,7 +7,7 @@ module.exports = {
sourceType: 'module',
},
plugins: ['ember', '@typescript-eslint', 'prettier'],
- extends: ['eslint:recommended', 'plugin:ember/recommended'],
+ extends: ['eslint:recommended', 'plugin:ember/recommended', 'prettier/@typescript-eslint'],
env: {
browser: true,
},
diff --git a/.gitbook.yaml b/.gitbook.yaml
new file mode 100644
index 000000000..15b3c4f3c
--- /dev/null
+++ b/.gitbook.yaml
@@ -0,0 +1,4 @@
+root: ./docs
+
+structure:
+ readme: ./index.md
diff --git a/README.md b/README.md
index f5d5d83fc..9c0d02d2b 100644
--- a/README.md
+++ b/README.md
@@ -89,7 +89,7 @@ ember install ember-decorators@^3.1.0 @ember-decorators/babel-transforms@^3.1.0
#### Update ember-decorators
-Follow the same process of deduplication, reinstallation, and re-deduplication as described for ember-cli-babel above. This will get you the latest version of ember-decorators and, importantly, its @ember-decorators/babel-transforms dependency.
+If you're on a version of Ember before 3.10, follow the same process of deduplication, reinstallation, and re-deduplication as described for ember-cli-babel above for ember-decorators. This will get you the latest version of ember-decorators and, importantly, its @ember-decorators/babel-transforms dependency.
#### Update ember-cli-typescript
diff --git a/config/addon-docs.js b/config/addon-docs.js
deleted file mode 100644
index 526890e86..000000000
--- a/config/addon-docs.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/* eslint-env node */
-'use strict';
-
-const AddonDocsConfig = require('ember-cli-addon-docs/lib/config');
-
-module.exports = class extends AddonDocsConfig {
- // See https://ember-learn.github.io/ember-cli-addon-docs/docs/deploying
- // for details on configuration you can override here.
- getRootURL() {
- return '';
- }
-};
diff --git a/config/deploy.js b/config/deploy.js
deleted file mode 100644
index b63fd6e58..000000000
--- a/config/deploy.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/* eslint-env node */
-'use strict';
-
-module.exports = function (deployTarget) {
- let ENV = {
- build: {},
- // include other plugin configuration that applies to all deploy targets here
- };
-
- if (deployTarget === 'development') {
- ENV.build.environment = 'development';
- // configure other plugins for development deploy target here
- }
-
- if (deployTarget === 'staging') {
- ENV.build.environment = 'production';
- // configure other plugins for staging deploy target here
- }
-
- if (deployTarget === 'production') {
- ENV.build.environment = 'production';
- // configure other plugins for production deploy target here
- }
-
- // Note: if you need to build some configuration asynchronously, you can return
- // a promise that resolves with the ENV object instead of returning the
- // ENV object synchronously.
- return ENV;
-};
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
new file mode 100644
index 000000000..c87d23eeb
--- /dev/null
+++ b/docs/SUMMARY.md
@@ -0,0 +1,31 @@
+# Table of contents
+
+* [ember-cli-typescript](index.md)
+* [Installation](installation.md)
+* [Configuration](configuration.md)
+* [TypeScript and Ember](ts/README.md)
+ * [Using TypeScript With Ember Effectively](ts/using-ts-effectively.md)
+ * [Decorators](ts/decorators.md)
+ * [Current limitations](ts/current-limitations.md)
+ * [Building Addons in TypeScript](ts/with-addons.md)
+ * [Understanding the `@types` Package Names](ts/package-names.md)
+* [Working With Ember](ember/README.md)
+ * [Components](ember/components.md)
+ * [Services](ember/services.md)
+ * [Routes](ember/routes.md)
+ * [Controllers](ember/controllers.md)
+ * [Helpers](ember/helpers.md)
+ * [Testing](ember/testing.md)
+* [Working With Ember Data](ember-data/README.md)
+ * [Models](ember-data/models.md)
+* [Cookbook](cookbook/README.md)
+ * [Working with route models](cookbook/working-with-route-models.md)
+* [Working With Ember Classic](legacy/README.md)
+ * [EmberComponent](legacy/ember-component.md)
+ * [Mixins](legacy/mixins.md)
+ * [Computed Properties](legacy/computed-properties.md)
+ * [EmberObject](legacy/ember-object.md)
+* [Upgrading from 1.x](upgrade-notes.md)
+* [Troubleshooting](troubleshooting/README.md)
+ * [Conflicting Type Dependencies](troubleshooting/conflicting-types.md)
+
diff --git a/tests/dummy/app/templates/docs/configuration.md b/docs/configuration.md
similarity index 67%
rename from tests/dummy/app/templates/docs/configuration.md
rename to docs/configuration.md
index 58f9d2cf3..128e1d9fd 100644
--- a/tests/dummy/app/templates/docs/configuration.md
+++ b/docs/configuration.md
@@ -1,50 +1,42 @@
-# Configuring ember-cli-typescript
+# Configuration
## Blueprints
-By default, ember-cli-typescript installs the [ember-cli-typescript-blueprints][blueprints] package so that you can use Ember's generators like normal, but with all the special sauce you need for things to work nicely throughout your system with TypeScript.
+By default, ember-cli-typescript installs the [ember-cli-typescript-blueprints](https://github.com/typed-ember/ember-cli-typescript-blueprints) package so that you can use Ember's generators like normal, but with all the special sauce you need for things to work nicely throughout your system with TypeScript.
-[blueprints]: https://github.com/typed-ember/ember-cli-typescript-blueprints
-
-If you want to stick with the normal JavaScript blueprints—say, because your team isn't ready to dive into the deep end with making *everything* TypeScript yet—you can simply uninstall the blueprints package.
+If you want to stick with the normal JavaScript blueprints—say, because your team isn't ready to dive into the deep end with making _everything_ TypeScript yet—you can simply uninstall the blueprints package.
With yarn:
-```sh
+```bash
yarn remove ember-cli-typescript-blueprints
```
With npm:
-```sh
+```bash
npm uninstall ember-cli-typescript-blueprints
```
## `tsconfig.json`
-We generate a good default [`tsconfig.json`][blueprint], which will usually make everything _Just Work™_. In general, you may customize your TypeScript build process as usual using the `tsconfig.json` file.
+We generate a good default [`tsconfig.json`](https://github.com/typed-ember/ember-cli-typescript/blob/master/blueprints/ember-cli-typescript/files/tsconfig.json), which will usually make everything _Just Work™_. In general, you may customize your TypeScript build process as usual using the `tsconfig.json` file.
However, there are a few things worth noting if you're already familiar with TypeScript and looking to make further or more advanced customizations (but _most_ users can just ignore this section!):
1. The generated tsconfig file does not set `"outDir"` and sets `"noEmit"` to `true`. The default configuration we generate allows you to run editors which use the compiler without creating extraneous `.js` files throughout your codebase, leaving the compilation to ember-cli-typescript to manage.
- You _can_ still customize those properties in `tsconfig.json` if your use case requires it, however. For example, to see the output of the compilation in a separate folder you are welcome to set `"outDir"` to some path and set `"noEmit"` to `false`. Then tools which use the TypeScript compiler (e.g. the watcher tooling in JetBrains IDEs) will generate files at that location, while the Ember.js/[Broccoli] pipeline will continue to use its own temp folder.
+ You _can_ still customize those properties in `tsconfig.json` if your use case requires it, however. For example, to see the output of the compilation in a separate folder you are welcome to set `"outDir"` to some path and set `"noEmit"` to `false`. Then tools which use the TypeScript compiler (e.g. the watcher tooling in JetBrains IDEs) will generate files at that location, while the Ember.js/[Broccoli](http://broccolijs.com/) pipeline will continue to use its own temp folder.
2. Closely related to the previous point: any changes you do make to `outDir` won't have any effect on how _Ember_ builds your application—we run the entire build pipeline through Babel's TypeScript support instead of through the TypeScript compiler.
-
-3. Since your application is built by Babel, and only *type-checked* by TypeScript, we set the `target` key in `tsconfig.json` to the current version of the ECMAScript standard so that type-checking uses the latest and greatest from the JavaScript standard library. The Babel configuration in your app's `config/targets.js` and any included polyfills will determine the final build output.
-
-4. If you make changes to the paths included in or excluded from the build via your `tsconfig.json` (using the `"include"`, `"exclude"`, or `"files"` keys), you will need to restart the server to take the changes into account: ember-cli-typescript does not currently watch the `tsconfig.json` file. For more details, see [the TypeScript reference materials for `tsconfig.json`][tsconfig].
-
-[blueprint]: https://github.com/typed-ember/ember-cli-typescript/blob/master/blueprints/ember-cli-typescript/files/tsconfig.json
-[Broccoli]: http://broccolijs.com/
-[tsconfig]: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
+3. Since your application is built by Babel, and only _type-checked_ by TypeScript, we set the `target` key in `tsconfig.json` to the current version of the ECMAScript standard so that type-checking uses the latest and greatest from the JavaScript standard library. The Babel configuration in your app's `config/targets.js` and any included polyfills will determine the final build output.
+4. If you make changes to the paths included in or excluded from the build via your `tsconfig.json` (using the `"include"`, `"exclude"`, or `"files"` keys), you will need to restart the server to take the changes into account: ember-cli-typescript does not currently watch the `tsconfig.json` file. For more details, see [the TypeScript reference materials for `tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).
## Enabling Sourcemaps
To enable TypeScript sourcemaps, you'll need to add the corresponding configuration for Babel to your `ember-cli-build.js` file:
-```ts
+```typescript
const app = new EmberApp(defaults, {
babel: {
sourceMaps: 'inline',
diff --git a/docs/cookbook/README.md b/docs/cookbook/README.md
new file mode 100644
index 000000000..0c7f30fd3
--- /dev/null
+++ b/docs/cookbook/README.md
@@ -0,0 +1,12 @@
+# Cookbook
+
+This “cookbook” section contains recipes for various scenarios you may encounter while working on your app or addon.
+
+{% hint style="info" %}
+Have an idea for an item that should fit here? [Open an issue for it!](https://github.com/typed-ember/ember-cli-typescript/issues/new/choose) We'd love to help you help us make this experience more awesome for everyone.
+{% endhint %}
+
+## Contents
+
+* [Working with route models](./working-with-route-models.md)
+
diff --git a/docs/cookbook/working-with-route-models.md b/docs/cookbook/working-with-route-models.md
new file mode 100644
index 000000000..dde3142e1
--- /dev/null
+++ b/docs/cookbook/working-with-route-models.md
@@ -0,0 +1,51 @@
+# Working with route models
+
+We often use routes’ models throughout our application, since they’re a core ingredient of our application’s data. As such, we want to make sure that we have good types for them!
+
+We can start by defining some type utilities to let us get the resolved value returned by a route’s model hook:
+
+```typescript
+import Route from '@ember/routing/route';
+
+/**
+ Get the resolved type of an item.
+
+ - If the item is a promise, the result will be the resolved value type
+ - If the item is not a promise, the result will just be the type of the item
+ */
+export type Resolved
= P extends Promise ? T : P;
+
+/** Get the resolved model value from a route. */
+export type ModelFrom = Resolved>;
+```
+
+How that works:
+
+* `Resolved
` says "if this is a promise, the type here is whatever the promise resolves to; otherwise, it's just the value"
+* `ReturnType` gets the return value of a given function
+* `R['model']` \(where `R` has to be `Route` itself or a subclass\) uses TS's mapped types to say "the property named `model` on `R`
+
+Putting those all together, `ModelFrom` ends up giving you the resolved value returned from the `model` hook for a given route:
+
+```typescript
+type MyRouteModel = ModelFrom;
+```
+
+## `model` on the controller
+
+We can use this functionality to guarantee that the `model` on a `Controller` is always exactly the type returned by `Route::model` by writing something like this:
+
+```typescript
+import Controller from '@ember/controller';
+import MyRoute from '../routes/my-route';
+import { ModelFrom } from '../lib/type-utils';
+
+export default class ControllerWithModel extends Controller {
+ declare model: ModelFrom;
+}
+```
+
+Now, our controller’s `model` property will _always_ stay in sync with the corresponding route’s model hook.
+
+**Note:** this _only_ works if you do not mutate the `model` in either the `afterModel` or `setupController` hooks on the route! That's generally considered to be a bad practice anyway. If you do change the type there, you'll need to define the type in some other way and make sure your route's model is defined another way.
+
diff --git a/docs/ember-data/README.md b/docs/ember-data/README.md
new file mode 100644
index 000000000..d80d997d8
--- /dev/null
+++ b/docs/ember-data/README.md
@@ -0,0 +1,6 @@
+# Working With Ember Data
+
+In this section, we cover how to use TypeScript effectively with specific Ember Data APIs \(anything you'd find under the `@ember-data` package namespace\).
+
+We do _not_ cover general usage of Ember Data; instead, we assume that as background knowledge. Please see the Ember Data [Guides](https://guides.emberjs.com/release/models) and [API docs](https://api.emberjs.com/ember-data/release)!
+
diff --git a/docs/ember-data/models.md b/docs/ember-data/models.md
new file mode 100644
index 000000000..549894743
--- /dev/null
+++ b/docs/ember-data/models.md
@@ -0,0 +1,124 @@
+# Models
+
+Ember Data models are normal TypeScript classes, but with properties decorated to define how the model represents an API resource and relationships to other resources. The decorators the library supplies "just work" with TypeScript at runtime, but require type annotations to be useful with TypeScript.
+
+For an overview of using Ember's decorators with TypeScript, see our overview.
+
+## `@attr`
+
+The type returned by the `@attr` decorator is whatever [Transform](https://api.emberjs.com/ember-data/release/classes/Transform) is applied via the invocation.
+
+* If you supply no argument to `@attr`, the value is passed through without transformation.
+* If you supply one of the built-in transforms, you will get back a corresponding type:
+ * `@attr('string')` → `string`
+ * `@attr(number)` → `number`,
+ * `@attr('boolean')` → `boolean`
+ * `@attr'date')` → `Date`
+* If you supply a custom transform, you will get back the type returned by your transform.
+
+So, for example, you might write a class like this:
+
+```typescript
+import Model, { attr } from '@ember-data/object';
+import CustomType from '../transforms/custom-transform';
+
+export default class User extends Model {
+ @attr()
+ name?: string;
+
+ @attr('number')
+ declare age: number;
+
+ @attr('boolean')
+ declare isAdmin: boolean;
+
+ @attr('custom-transform')
+ declare myCustomThing: CustomType;
+}
+```
+
+**Very important:** Even more than with decorators in general, you should be careful when deciding whether to mark a property as optional `?` or definitely present \(no annotation\): Ember Data will default to leaving a property empty if it is not supplied by the API or by a developer when creating it. That is: the _default_ for Ember corresponds to an optional field on the model.
+
+The _safest_ type you can write for an Ember Data model, therefore, leaves every property optional: this is how models _actually_ behave. If you choose to mark properties as definitely present by leaving off the `?`, you should take care to guarantee that this is a guarantee your API upholds, and that ever time you create a record from within the app, _you_ uphold those guarantees.
+
+One way to make this safer is to supply a default value using the `defaultValue` on the options hash for the attribute:
+
+```typescript
+import Model, { attr } from '@ember-data/object';
+
+export default class User extends Model {
+ @attr()
+ declare name?: string;
+
+ @attr('number', { defaultValue: 13 })
+ declare age: number;
+
+ @attr('boolean', { defaultValue: false })
+ declare isAdmin: boolean;
+}
+```
+
+## `@belongsTo`
+
+The type returned by the `@hasMany` decorator depends on whether the relationship is `{ async: true }` \(which it is by default\).
+
+* If the value is `true`, the type you should use is `DS.PromiseObject`, where `Model` is the type of the model you are creating a relationship to.
+* If the value is `false`, the type is `Model`, where `Model` is the type of the model you are creating a relationship to.
+
+So, for example, you might define a class like this:
+
+```typescript
+import Model, { belongsTo } from '@ember-data/model';
+import DS from 'ember-data'; // NOTE: this is a workaround, see discussion below!
+import User from './user';
+import Site from './site';
+
+export default class Post extends Model {
+ @belongsTo('user')
+ declare user: DS.PromiseObject;
+
+ @belongsTo('site', { async: false })
+ declare site: Site;
+}
+```
+
+These are _type_-safe to define as always present, that is to leave off the `?` optional marker:
+
+* accessing an async relationship will always return a `PromiseObject`, which itself may or may not ultimately resolve to a value—depending on the API response—but will always be present itself.
+* accessing a non-async relationship which is known to be associated but has not been loaded will trigger an error, so all access to the property will be safe _if_ it resolves at all.
+
+Note, however, that this type-safety is not a guarantee of there being no runtime error: you still need to uphold the contract for non-async relationships \(that is: loading the data first, or side-loading it with the request\) to avoid throwing an error!
+
+## `@hasMany`
+
+The type returned by the `@hasMany` decorator depends on whether the relationship is `{ async: true }` \(which it is by default\).
+
+* If the value is `true`, the type you should use is `DS.PromiseManyArray`, where `Model` is the type of the model you are creating a relationship to.
+* If the value is `false`, the type is `EmberArray`, where `Model` is the type of the model you are creating a relationship to.
+
+So, for example, you might define a class like this:
+
+```typescript
+import Model, { hasMany } from '@ember-data/model';
+import EmberArray from '@ember/array';
+import DS from 'ember-data'; // NOTE: this is a workaround, see discussion below!
+import Comment from './comment';
+import User from './user';
+
+export default class Thread extends Model {
+ @hasMany('comment')
+ declare comment: DS.PromiseManyArray;
+
+ @hasMany('user', { async: false })
+ declare participants: EmberArray;
+}
+```
+
+The same basic rules about the safety of these lookups as with `@belongsTo` apply to these types. The difference is just that in `@hasMany` the resulting types are _arrays_ rather than single objects.
+
+## Importing `PromiseObject` and `PromiseManyArray`
+
+There is no public import path in the [Ember Data Packages](https://emberjs.github.io/rfcs/0395-ember-data-packages.html) API for the `PromiseObject` and `PromiseManyArray` types. These types are slowly being disentangled from Ember Data and will eventually be removed. However, until they are, we need a way to refer to them. For _now_, the best option is to refer to them via the legacy `DS` import.
+
+In the future, they will become unnecesary, as the types will simply be `Promise` and `Promise>`.
+
diff --git a/docs/ember/README.md b/docs/ember/README.md
new file mode 100644
index 000000000..d3f40bf1b
--- /dev/null
+++ b/docs/ember/README.md
@@ -0,0 +1,15 @@
+# Working With Ember
+
+In this section, we cover how to use TypeScript effectively with specific Ember APIs \(anything you'd find under the `@ember` package namespace\).
+
+We do _not_ cover general usage of Ember; instead, we assume that as background knowledge. Please see the Ember [Guides](https://guides.emberjs.com/release/) and [API docs](https://api.emberjs.com/ember/release)!
+
+## Outline
+
+* [Controllers](ember/controllers.md)
+* [Services](ember/services.md)
+* [Overview: Ember](ember/overview.md)
+* [Testing](ember/testing.md)
+* [Components](ember/components.md)
+* [Helpers](ember/helpers.md)
+* [Routes](ember/routes.md)
diff --git a/docs/ember/components.md b/docs/ember/components.md
new file mode 100644
index 000000000..b6f67ed9c
--- /dev/null
+++ b/docs/ember/components.md
@@ -0,0 +1,195 @@
+# Components
+
+{% hint style="info" %}
+New to Ember or the Octane edition specifically? You may want to read [the Ember Guides’ material on `Component`s](https://guides.emberjs.com/release/components/) first!
+{% endhint %}
+
+Glimmer Components are defined in one of three ways: with templates only, with a template and a backing class, or with only a backing class \(i.e. a `yield`-only component\). When using a backing class, you get a first-class experience using TypeScript! Unfortunately, we don’t yet support type-checking for templates, but we hope to build that out eventually. Don’t let that stop you, though: types in your component classes make for a great experience, so let’s dig in and see how it works in practice.
+
+## A simple component
+
+A _very_ simple Glimmer component which lets you change the count of a value might look like this:
+
+```text
+
+{{this.count}}
+
+```
+
+```typescript
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { action } from '@ember/object';
+
+export default class Counter extends Component {
+ @tracked count = 0;
+
+ @action plus() {
+ this.count += 1;
+ }
+
+ @action minus() {
+ this.count -= 1;
+ }
+}
+```
+
+Notice that there are no type declarations here – but this _is_ actually a well-typed component. The type of `count` is `number`, and if we accidentally wrote something like `this.count = "hello"` the compiler would give us an error.
+
+## Adding arguments
+
+So far so good, but of course most components aren’t quite this simple! Instead, they’re invoked by other templates and they can invoke other components themselves in their own templates.
+
+Glimmer components can receive both _arguments_ and _attributes_ when they are invoked. When you are working with a component’s backing class, you have access to the arguments but _not_ to the attributes. The arguments are passed to the constructor, and then available as `this.args` on the component instance afterward. Let’s imagine a component which just logs the names of its arguments when it is first constructed:
+
+```typescript
+import Component from '@glimmer/component';
+
+const log = console.log.bind(console);
+
+export default class ArgsDisplay extends Component {
+ constructor(owner: unknown, args: {}) {
+ super(owner, args);
+
+ Object.keys(args).forEach(log);
+ }
+}
+```
+
+{% hint style="info" %}
+If you’re used to the classic Ember Object model, there are two important differences in the constructor itself:
+
+* we use `super` instead of `this._super`
+* we _must_ call `super` before we do anything else with `this`, because in a subclass `this` is set up by running the superclass's constructor first \(as implied by [the JavaScript spec](https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation)\)
+{% endhint %}
+
+Notice that we have to start by calling `super` with `owner` and `args`. This may be a bit different from what you’re used to in Ember or other frameworks, but is normal for sub-classes in TypeScript today. If the compiler just accepted any `...arguments`, a lot of potentially _very_ unsafe invocations would go through. So, instead of using `...arguments`, we explicitly pass the _specific_ arguments and make sure their types match up with what the super-class expects.
+
+{% hint style="info" %}
+This might change in the future! If TypeScript eventually adds [support for “variadic kinds”](https://github.com/Microsoft/TypeScript/issues/5453), using `...arguments` could become safe.
+{% endhint %}
+
+The types for `owner` here and `args` line up with what the `constructor` for Glimmer components expect. The `owner` is specified as `unknown` because this is a detail we explicitly _don’t_ need to know about. The `args` are `{}` because a Glimmer component _always_ receives an object containing its arguments, even if the caller didn’t pass anything: then it would just be an empty object.
+
+`{}` is an empty object type – all objects extend from it, but there will be no properties on it. This is distinct from the `object` type, which the TypeScript docs describe as:
+
+> any thing that is not `number`, `string`, `boolean`, `symbol`, `null`, or `undefined`.
+
+If we used `object`, we could end up with TypeScript thinking `args` were an array, or a `Set`, or anything else that isn’t a primitive. Since we have `{}`, we _know_ that it's an object.
+
+{% hint style="info" %}
+For some further details, check out [this blog post](https://mariusschulz.com/blog/the-object-type-in-typescript).
+{% endhint %}
+
+The `args` passed to a Glimmer Component [are available on `this`](https://github.com/glimmerjs/glimmer.js/blob/2f840309f013898289af605abffe7aee7acc6ed5/packages/%40glimmer/component/src/component.ts#L12), so we could change our definition to return the names of the arguments from a getter:
+
+```typescript
+import Component from '@glimmer/component';
+
+export default class ArgsDisplay extends Component {
+ get argNames(): string[] {
+ return Object.keys(this.args);
+ }
+}
+```
+
+```text
+
The names of the @args are:
+
+ {{#each this.argNames as |argName|}}
+
{{argName}}
+ {{/each}}
+
+```
+
+### Understanding `args`
+
+Now, looking at that bit of code, you might be wondering how it knows what the type of `this.args` is. In the `constructor` version, we explicitly _named_ the type of the `args` argument. Here, it seems to just work automatically. This works because the type definition for a Glimmer component looks roughly like this:
+
+```typescript
+export default class Component {
+ readonly args: Args;
+
+ constructor(owner: unknown, args: Args);
+}
+```
+
+{% hint style="info" %}
+Not sure what’s up with `` _at all_? We highly recommend the [TypeScript Deep Dive](https://basarat.gitbooks.io/typescript/) book’s [chapter on generics ](https://basarat.gitbooks.io/typescript/docs/types/generics.html) to be quite helpful in understanding this part.
+{% endhint %}
+
+The type signature for Component, with `Args extends {} = {}`, means that the component _always_ has a property named `args` —
+
+* with the type `Args`
+* which can be anything that extends the type `{}` – an object
+* and _defaults_ to being just an empty object – `= {}`
+
+This is analogous to the type of `Array` : since you can have an array of `string` , or an array of `number` or an array of `SomeFancyObject` , the type of array is `Array` , where `T` is the type of thing in the array, which TypeScript normally figures out for you automatically at compile time:
+
+```typescript
+let a = [1, 2, 3]; // Array
+let b = ["hello", "goodbye"]; // Array
+```
+
+In the case of the Component, we have the types the way we do so that you can’t accidentally define `args` as a string, or `undefined` , or whatever: it _has_ to be an object. Thus, `Component` . But we also want to make it so that you can just write `extends Component` , so that needs to have a default value. Thus, `Component`.
+
+### Giving `args` a type
+
+Now let’s put this to use. Imagine we’re constructing a user profile component which displays the user’s name and optionally an avatar and bio. The template might look something like this:
+
+```text
+
+ {{#if this.avatar}}
+
+ {{/if}}
+
{{this.userInfo}}
+
+```
+
+Then we could capture the types for the profile with an interface representing the _arguments_:
+
+```typescript
+import Component from '@glimmer/component';
+import { generateUrl } from '../lib/generate-avatar';
+
+interface User {
+ name: string;
+ avatar?: string;
+ bio?: string;
+}
+
+export default class UserProfile extends Component {
+ get userInfo(): string {
+ return this.args.bio ? `${this.args.name} ${this.args.bio}` : this.args.name;
+ }
+
+ get avatar(): string {
+ return this.args.avatar ?? generateUrl();
+ }
+}
+```
+
+Assuming the default `tsconfig.json` settings \(with `strictNullChecks: true`\), this wouldn't type-check if we didn't _check_ whether the `bio` argument were set.
+
+## Generic subclasses
+
+If you'd like to make your _own_ component subclass-able, you need to make it generic as well.
+
+{% hint style="warning" %}
+Are you sure you want to provide an inheritance-based API? Oftentimes, it's easier to maintain \(and involves less TypeScript hoop-jumping\) to use a compositional API instead. If you're sure, here's how!
+{% endhint %}
+
+```typescript
+import Component from '@glimmer/component';
+
+export interface FancyInputArgs {
+ // ...
+}
+
+export default class FancyInput extends Component {
+ // ...
+}
+```
+
+Requiring that `Args extends FancyInputArgs` means that subclasses can have _more_ than these args, but not _fewer_. Specifying that the `Args = FancyInputArgs` means that they _default_ to just being `FancyInputArgs`, so users don't need to supply an explicit generic type parameter here unless they're adding more arguments to the class.
+
diff --git a/docs/ember/controllers.md b/docs/ember/controllers.md
new file mode 100644
index 000000000..06153598e
--- /dev/null
+++ b/docs/ember/controllers.md
@@ -0,0 +1,49 @@
+# Controllers
+
+Like [routes](./routes.md), controllers are just normal classes with a few special Ember lifecycle hooks and properties available.
+
+The main thing you need to be aware of is special handling around query params. In order to provide type safety for query param configuration, Ember's types specify that when defining a query param's `type` attribute, you must supply one of the allowed types: `'boolean'`, `'number'`, `'array'`, or `'string'` \(the default\). However, if you supply these types as you would in JS, like this:
+
+```typescript
+import Controller from "@ember/controller";
+
+export default class HeyoController extends Controller {
+ queryParams = [
+ {
+ category: { type: "array" },
+ },
+ ];
+}
+```
+
+Then you will see a type error like this:
+
+```text
+Property 'queryParams' in type 'HeyoController' is not assignable to the same property in base type 'Controller'.
+ Type '{ category: { type: string; }; }[]' is not assignable to type '(string | Record)[]'.
+ Type '{ category: { type: string; }; }' is not assignable to type 'string | Record'.
+ Type '{ category: { type: string; }; }' is not assignable to type 'Record'.
+ Property 'category' is incompatible with index signature.
+ Type '{ type: string; }' is not assignable to type 'string | QueryParamConfig | undefined'.
+ Type '{ type: string; }' is not assignable to type 'QueryParamConfig'.
+ Types of property 'type' are incompatible.
+ Type 'string' is not assignable to type '"string" | "number" | "boolean" | "array" | undefined'.ts(2416)
+```
+
+This is because TS currently infers the type of `type: "array"` as `type: string`. You can work around this by supplying `as const` after the declaration:
+
+```diff
+import Controller from "@ember/controller";
+
+export default class HeyoController extends Controller {
+ queryParams = [
+ {
+- category: { type: "array" },
++ category: { type: "array" as const },
+ },
+ ];
+}
+```
+
+Now it will type-check.
+
diff --git a/docs/ember/helpers.md b/docs/ember/helpers.md
new file mode 100644
index 000000000..686a7c699
--- /dev/null
+++ b/docs/ember/helpers.md
@@ -0,0 +1,139 @@
+# Helpers
+
+Helpers in Ember are just functions or classes with a well-defined interface, which means they largely Just Work™ with TypeScript. However, there are a couple things you’ll want to watch out for.
+
+{% hint style="info" %}
+As always, you should start by reading and understanding the [Ember Guide on Helpers](https://guides.emberjs.com/release/templates/writing-helpers/)!
+{% endhint %}
+
+## Function-based helpers
+
+The basic type of a helper function in Ember is:
+
+```typescript
+type FunctionBasedHelper =
+ (positional: unknown[], named: Record) => string | void;
+```
+
+This represents a function which _may_ have an arbitrarily-long list of positional arguments, which _may_ be followed by a single dictionary-style object containing any named arguments.
+
+There are three important points about this definition:
+
+1. `positional` is an array of `unknown`, of unspecified length.
+2. `named` is a `Record`.
+3. Both arguments are always set, but may be empty.
+
+Let’s walk through each of these.
+
+### Handling `positional` arguments
+
+The type is an array of `unknown` because we don’t \(yet!\) have any way to make templates aware of the information in this definition—so users could pass in _anything_. We can work around this using [type narrowing](https://microsoft.github.io/TypeScript-New-Handbook/chapters/narrowing/)—TypeScript’s way of using runtime checks to inform the types at runtime.
+
+```typescript
+function totalLength(positional: unknown[]) {
+ // Account for case where user passes no arguments
+ assert(
+ 'all positional args to `total-length` must be strings',
+ positional.every(arg => typeof arg === 'string')
+ );
+
+ // safety: we can cast `positional as string[]` because we asserted above
+ return (positional as string[]).reduce((sum, s) => sum + s.length, 0);
+}
+```
+
+### Handling `named` arguments
+
+We specified the type of `named` as a `Record`. `Record` is a built-in TypeScript type representing a fairly standard type in JavaScript: an object being used as a simple map of keys to values. Here we set the values to `unknown` and the keys to `string`, since that accurately represents what callers may actually pass to a helper.
+
+\(As with `positional`, we specify the type here as `unknown` to account for the fact that the template layer isn’t aware of types yet.\)
+
+### `positional` and `named` presence
+
+Note that even if the user passes _no_ arguments, both `positional` and `named` are always present. They will just be _empty_ in that case. For example:
+
+```typescript
+import { helper } from '@ember/component/helper';
+
+const describe = (entries: string): string => (entries.length > 0 ? entries : '(none)');
+
+export function showAll(positional: unknown[], named: Record) {
+ // pretty print each item with its index, like `0: { neat: true }` or
+ // `1: undefined`.
+ const positionalEntries = positional
+ .reduce((items, arg, index) => items.concat(`${index}: ${JSON.stringify(arg)}`), [])
+ .join(', ');
+
+ // pretty print each item with its name, like `cool: beans` or
+ // `answer: 42`.
+ const namedEntries = Object.keys(named)
+ .reduce(
+ (items, key) => items.concat(`${key}: ${JSON.stringify(named[key], undefined, 2)}`),
+ []
+ )
+ .join(', ');
+
+ return `positional: ${describe(positionalEntries)}\nnamed: ${describe(namedEntries)}`;
+}
+
+export default helper(showAll);
+```
+
+### Putting it all together
+
+Given those constraints, let’s see what a \(very contrived\) actual helper might look like in practice. Let’s imagine we want to take a pair of strings and join them with a required separator and optional prefix and postfixes:
+
+```typescript
+import { helper } from '@ember/component/helper';
+import { assert } from '@ember/debug';
+import { is } from '../../type-utils'
+
+export function join(positional: [unknown, unknown], named: Dict) {
+ assert(
+ `'join' requires two 'string' positional parameters`,
+ is<[string, string]>(
+ positional,
+ positional.length === 2 &&
+ positional.every(el => typeof el === 'string')
+ )
+ );
+ assert(`'join' requires argument 'separator'`, typeof named.separator === 'string');
+
+ const joined = positional.join(named.separator);
+ const prefix = typeof named.prefix === 'string' ? named.prefix : '';
+
+ return `${prefix}${joined}`;
+}
+
+export default helper(join);
+```
+
+## Class-based helpers
+
+The basic type of a class-based helper function in Ember is:
+
+```typescript
+interface ClassBasedHelper {
+ compute(positional?: unknown[], named?: Record): string | void;
+}
+```
+
+Notice that the signature of `compute` is the same as the signature for the function-based helper! This means that everything we said above applies in exactly the same way here. The only differences are that we can have local state and, by extending from Ember’s `Helper` class, we can hook into the dependency injection system and use services.
+
+```typescript
+import Helper from '@ember/component/helper';
+import { inject as service } from '@ember/service';
+import Authentication from 'my-app/services/authentication';
+
+export default class Greet extends Helper {
+ @service authentication: Authentication;
+
+ compute() {
+ return this.authentication.isAuthenticated
+ ? `Welcome back, ${authentication.userName}!`
+ : 'Sign in?';
+}
+```
+
+For more details on using decorators, see our [guide to using decorators](https://github.com/typed-ember/ember-cli-typescript/tree/3a434def8b8c8214853cea0762940ccedb2256e8/docs/ember/%28../ts/decorators/%29/README.md). For details on using services, see our [guide to services](https://github.com/typed-ember/ember-cli-typescript/tree/3a434def8b8c8214853cea0762940ccedb2256e8/docs/ember/%28./services/%29/README.md).
+
diff --git a/docs/ember/routes.md b/docs/ember/routes.md
new file mode 100644
index 000000000..c42e6f69d
--- /dev/null
+++ b/docs/ember/routes.md
@@ -0,0 +1,38 @@
+# Routes
+
+Working with Routes is in general just working normal TypeScript classes. Ember's types supply the definitions for the various lifecycle events available within route subclasses, which will provide autocomplete and type-checking along the way in general.
+
+However, there is one thing to watch out for: the types of the arguments passed to methods will _not_ autocomplete as you may expect. This is because in _general_ a subclass may override a superclass method as long as it calls its superclass's method correctly. This is very bad practice, but it is legal JavaScript! This is never a concern for lifecyclehooks in Ember, because they are called by the framework itself. However, TypeScript does not and cannot know that, so we have to provide the types directly.
+
+Accordingly, and because the `Transition` type is not currently exported as a public type, you may find it convenient to define it using TypeScript's `ReturnType` utility type, which does exactly what it sounds like and gives us a local type which is the type returned by some function. The `RouterService.transitionTo` returns a `Transition`, so we can rely on that as stable public API to define `Transition` locally ourselves:
+
+```typescript
+import Route from '@ember/routing/route';
+import type RouterService from '@ember/routing/router-service';
+type Transition = ReturnType;
+
+export default class MyRoute extends Route {
+ beforeModel(transition: Transition) {
+ // ...
+ }
+}
+```
+
+This inconsistency will be solved in the future. For now, this workaround gets the job done, and also shows the way to using this information to provide the type of the route's model to other consumers: see [Working with Route Models](routes.md) for details!
+
+```typescript
+import Route from '@ember/routing/route';
+
+type Resolved = T extends Promise : U : T;
+
+export type MyRouteModel = Resolved>;
+
+export default class MyRoute extends Route {
+ model() {
+ // ...
+ }
+}
+```
+
+The `Resolved` utility type takes in any type, and if the type is a `Promise` it transforms the type into whatever the `Promise` resolves to; otherwise it just returns the same type. As we saw above, `ReturnType` gets us the return type of the function. So our final `MyRouteModel` type takes the return type from our `model` hook, and uses the `Resolved` type to get the type the promise will resolve to—that is, exactly the type we will have available as `@model` in the template and as `this.model` on a controller. This in turn allows us to use
+
diff --git a/docs/ember/services.md b/docs/ember/services.md
new file mode 100644
index 000000000..3a48bd0c8
--- /dev/null
+++ b/docs/ember/services.md
@@ -0,0 +1,136 @@
+# Services
+
+Ember Services are global singleton classes that can be made available to different parts of an Ember application via dependency injection. Due to their global, shared nature, writing services in TypeScript gives you a build-time-enforcable API for some of the most central parts of your application.
+
+{% hint style="info" %}
+If you are not familiar with Services in Ember, first make sure you have read and understood the [Ember Guide on Services](https://guides.emberjs.com/release/services/)!
+{% endhint %}
+
+## A basic service
+
+Let's take this example from the [Ember Guide](https://guides.emberjs.com/release/services/):
+
+```typescript
+import { A } from '@ember/array';
+import Service from '@ember/service';
+
+export default class ShoppingCartService extends Service {
+ items = A([]);
+
+ add(item) {
+ this.items.pushObject(item);
+ }
+
+ remove(item) {
+ this.items.removeObject(item);
+ }
+
+ empty() {
+ this.items.clear();
+ }
+}
+```
+
+Just making this a TypeScript file gives us some type safety without having to add any additional type information. We'll see this when we use the service elsewhere in the application.
+
+{% hint style="info" %}
+When working in Octane, you're better off using a `TrackedArray` from [tracked-built-ins](https://github.com/pzuraq/tracked-built-ins) instead of the classic EmberArray:
+
+```typescript
+import { TrackedArray } from 'tracked-built-ins';
+import Service from '@ember/service';
+
+export default class ShoppingCartService extends Service {
+ items = new TrackedArray();
+
+ add(item) {
+ this.items.push(item);
+ }
+
+ remove(item) {
+ this.items.splice(1, this.items.findIndex((i) => i === item));
+ }
+
+ empty() {
+ this.items.clear();
+ }
+}
+```
+
+Notice that here we are using only built-in array operations, not Ember's custom array methods.
+{% endhint %}
+
+## Using services
+
+You can use a service in any container-resolved object such as a component or another service. Services are injected into these objects by decorating a property with the `inject` decorator. Because decorators can't affect the type of the property they decorate, we must manually type the property. Also, we must use `declare` modifier to tell the TypeScript compiler to trust that this property will be set up by something outside this component—namely, the decorator.
+
+Here's an example of using the `ShoppingCartService` we defined above in a component:
+
+```typescript
+import Component from '@glimmer/component';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+
+import ShoppingCartService from 'my-app/services/shopping-cart';
+
+export default class CartContentsComponent extends Component {
+ @service declare shoppingCart: ShoppingCartService;
+
+ @action
+ remove(item) {
+ this.shoppingCart.remove(item);
+ }
+}
+```
+
+Any attempt to access a property or method not defined on the service will fail type-checking:
+
+```typescript
+import Component from '@glimmer/component';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+
+import ShoppingCartService from 'my-app/services/shopping-cart';
+
+export default class CartContentsComponent extends Component {
+ @service declare shoppingCart: ShoppingCartService;
+
+ @action
+ remove(item) {
+ // Error: Property 'saveForLater' does not exist on type 'ShoppingCartService'.
+ this.shoppingCart.saveForLater(item);
+ }
+}
+```
+
+Services can also be loaded from the dependency injection container manually:
+
+```typescript
+import Component from '@glimmer/component';
+import { getOwner } from '@ember/application';
+import { action } from '@ember/object';
+
+import ShoppingCartService from 'my-app/services/shopping-cart';
+
+export default class CartContentsComponent extends Component {
+ get cart() {
+ return getOwner(this).lookup('service:shopping-cart') as ShoppingCartService;
+ }
+
+ @action
+ remove(item) {
+ this.cart.remove(item);
+ }
+}
+```
+
+Here we need to cast the lookup result to `ShoppingCartService` in order to get any type-safety because the lookup return type is `any` \(see caution below\).
+
+{% hint style="danger" %}
+This type-cast provides no guarantees that what is returned by the lookup is actually the service you are expecting. Because TypeScript cannot resolve the lookup micro-syntax \(`service:`\) to the service class, a typo would result in returning something other than the specified type. It only gurantees that _if_ the expected serbice is returned that you are using it correctly.
+
+There is a merged \(but not yet implemented\) [RFC](https://emberjs.github.io/rfcs/0585-improved-ember-registry-apis.html) which improves this design and makes it straightforward to type-check. Additionally, TypeScript 4.1's introduction of [template types](https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#template-literal-types) may allow us to supply types that work with the microsyntax.
+
+For now, however, remember that _the cast is unsafe_!
+{% endhint %}
+
diff --git a/docs/ember/testing.md b/docs/ember/testing.md
new file mode 100644
index 000000000..e7f85d34e
--- /dev/null
+++ b/docs/ember/testing.md
@@ -0,0 +1,338 @@
+# Testing
+
+Testing with TypeScript mostly works just the same as you'd expect in a non-TypeScript Ember application—so if you're just starting out with Ember, we recommend you read the official Ember [Testing Guides](https://guides.emberjs.com/release/testing/) first. The rest of this guide assumes you're already comfortable with testing in Ember!
+
+When working with TypeScript in Ember tests, there are a few differences in your experience, and there are also differences in how you should handle testing app code vs. addon code.
+
+## App tests
+
+One major difference when working with TypeScript in _app_ code is that once your app is fully converted, there are a bunch of kinds of tests you just don't need to write any more: things like testing bad inputs to functions. We'll use an admittedly silly and contrived example here, an `add` function to add two numbers together, so that we can focus on the differences between JavaScript and TypeScript, rather than getting hung up on the details of this particular function.
+
+First, the function we're testing might look like this.
+
+{% hint style="info" %}
+Here we’re using the `assert` from `@ember/debug`. If you’re not familiar with it, you might want to take a look at its [API docs](https://api.emberjs.com/ember/3.14/functions/@ember%2Fdebug/assert)! It’s a development-and-test-only helper that gets stripped from production builds, and is very helpful for this kind of thing!
+{% endhint %}
+
+```javascript
+// app/utils/math.js
+
+export function add(a, b) {
+ assert(
+ 'arguments must be numbers',
+ typeof a === number && typeof b === number
+ );
+
+ return a + b;
+}
+```
+
+Then the test for it might look something like this:
+
+```javascript
+// tests/unit/utils/math-test.js
+
+import { module, test } from 'qunit';
+import { add } from 'app/utils/math';
+
+module('the `add` function', function(hooks) {
+ test('adds numbers correctly', function(assert) {
+ assert.equal('2 + 2 is 4', add(2, 2), 4);
+ assert.notEqual('2 + 2 is a number', add(2, 2), NaN);
+ assert.notEqual('2 + 2 is not infinity', add(2, 2), Infinity);
+ });
+
+ test('throws an error with strings', function(assert) {
+ assert.throws(
+ 'when the first is a string and the second is a number',
+ () => add('hello', 1)
+ );
+ assert.throws(
+ 'when the first is a number and the second is a string',
+ () => add(0, 'hello')
+ );
+ assert.throws(
+ 'when both are strings',
+ () => add('hello', 'goodbye')
+ );
+ })
+});
+```
+
+In TypeScript, that wouldn't make any sense at all, because we'd simply add the types to the function declaration:
+
+```typescript
+// app/utils/math.ts
+
+export function add(a: number, b: number): number {
+ assert(
+ 'arguments must be numbers',
+ typeof a === number && typeof b === number
+ );
+
+ return a + b;
+}
+```
+
+We might still write tests to make sure what we actually got back was what we expected—
+
+```typescript
+// tests/unit/utils/math-test.ts
+
+import { module, test } from 'qunit';
+import { add } from 'app/utils/math';
+
+module('the `add` function', function(hooks) {
+ test('adds numbers correctly', function(assert) {
+ assert.equal('2 + 2 is 4', add(2, 2), 4);
+ assert.notEqual('2 + 2 is a number', add(2, 2), NaN);
+ assert.notEqual('2 + 2 is not infinity', add(2, 2), Infinity);
+ });
+});
+```
+
+—but there are a bunch of things we _don't_ need to test. All of those special bits of handling for the case where we pass in a `string` or `undefined` or whatever else? We can drop that. Notice, too, that we can drop the assertion from our function definition, because the _compiler_ will check this for us:
+
+```typescript
+// app/utils/math.ts
+
+export function add(a: number, b: number): number {
+ return a + b;
+}
+```
+
+## Addon tests
+
+Note, however, that this _only_ applies to _app code_. If you're writing an Ember addon \(or any other library\), you cannot assume that everyone consuming your code is using TypeScript. You still need to account for these kinds of cases. This will require you to do something that probably feels a bit gross: casting a bunch of values `as any` for your tests, so that you can test what happens when people feed bad data to your addon!
+
+Let's return to our silly example with an `add` function. Our setup will look a lot like it did in the JavaScript-only example—but with some extra type coercions along the way so that we can invoke it the way JavaScript-only users might.
+
+First, notice that in this case we’ve added back in our `assert` in the body of the function. The inputs to our function here will get checked for us by any TypeScript users, but this way we are still doing the work of helping out our JavaScript users.
+
+```typescript
+function add(a: number, b: number): number {
+ assert(
+ 'arguments must be numbers',
+ typeof a === number && typeof b === number
+ );
+
+ return a + b;
+}
+```
+
+Now, back in our test file, we’re similarly back to testing all those extra scenarios, but here TypeScript would actually stop us from even having these tests work _at all_ if we didn’t use the `as` operator to throw away what TypeScript knows about our code!
+
+```javascript
+// tests/unit/utils/math-test.js
+
+import { module, test } from 'qunit';
+import { add } from 'app/utils/math';
+
+module('the `add` function', function(hooks) {
+ test('adds numbers correctly', function(assert) {
+ assert.equal('2 + 2 is 4', add(2, 2), 4);
+ assert.notEqual('2 + 2 is a number', add(2, 2), NaN);
+ assert.notEqual('2 + 2 is not infinity', add(2, 2), Infinity);
+ });
+
+ test('throws an error with strings', function(assert) {
+ assert.throws(
+ 'when the first is a string and the second is a number',
+ () => add('hello' as any, 1)
+ );
+ assert.throws(
+ 'when the first is a number and the second is a string',
+ () => add(0, 'hello' as any)
+ );
+ assert.throws(
+ 'when both are strings',
+ () => add('hello' as any, 'goodbye' as any)
+ );
+ })
+});
+```
+
+## Gotchas
+
+### The `TestContext`
+
+A common scenario in Ember tests, especially integration tests, is setting some value on the `this` context of the tests, so that it can be used in the context of the test. For example, we might need to set up a `User` type to pass into a `Profile` component.
+
+We’re going to start by defining a basic `User` and `Profile` so that we have a good idea of what we’re testing.
+
+The `User` type is very simple, just an `interface`:
+
+```typescript
+// app/types/user.ts
+
+export default interface User {
+ displayName: string;
+ avatarUrl?: string;
+}
+```
+
+Then our component might be defined like this:
+
+```text
+{{! app/components/profile.hbs }}
+
+
+
+ {{@displayName}}
+
+```
+
+```typescript
+import Component from '@glimmer/component';
+import User from 'app/types/user';
+import { randomAvatarURL } from 'app/utils/avatar';
+
+export default class Profile extends Component {
+ get avatar() {
+ return this.args.avatar ?? randomAvatarURL();
+ }
+
+ get description() {
+ return this.args.avatar
+ ? `${this.args.displayName}'s custom profile picture`
+ : 'a randomly generated placeholder avatar';
+ }
+}
+```
+
+{% hint style="info" %}
+Not familiar with how we define a Glimmer `Component` and its arguments? Check out [our guide](https://github.com/typed-ember/ember-cli-typescript/tree/3a434def8b8c8214853cea0762940ccedb2256e8/docs/ember/components/README.md)!
+{% endhint %}
+
+Now, with that setup out of the way, let’s get back to talking about the text context! We need to set up a `User` to pass into the test. With TypeScript on our side, we can even make sure that it actually matches up to the type we want to use!
+
+```typescript
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+import User from 'app/types/user';
+
+module('Integration | Component | Profile', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('given a user with an avatar', async function(assert) {
+ this.user: User = {
+ displayName: 'Rey',
+ avatar: 'https://example.com/star-wars/rey',
+ };
+
+ await render(hbs` TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
+> —[typescriptlang.org](http://www.typescriptlang.org)
+
+TypeScript lets you build _ambitious web applications_ with confidence—so it’s a perfect fit for Ember apps!
+
+* Get rid of `undefined is not a function` and `null is not an object` once and for all.
+* Enjoy API docs… that are always up-to-date.
+* Experience better developer productivity through top-notch editor support, including incredible autocomplete, guided refactorings, automatic imports, and more.
+
diff --git a/docs/installation.md b/docs/installation.md
new file mode 100644
index 000000000..e45c4652d
--- /dev/null
+++ b/docs/installation.md
@@ -0,0 +1,38 @@
+# Installation
+
+You can simply `ember install` the dependency like normal:
+
+```bash
+ember install ember-cli-typescript@latest
+```
+
+All dependencies will be added to your `package.json`, and you're ready to roll!
+
+**If you're upgrading from a previous release, see (./upgrade-notes.md).**
+
+Installing ember-cli-typescript modifies your project in two ways:
+
+* installing a number of other packages to make TypeScript work in your app or addon
+* generating a number of files in your project
+
+## Other packages this addon installs
+
+We install all of the following packages at their current "latest" value, :
+
+* `typescript`
+* `ember-cli-typescript-blueprints`
+* `@types/ember`
+* `@types/ember-data`
+* `@types/ember__*` – `@types/ember__object` for `@ember/object` etc.
+* `@types/ember-data__*` – `@types/ember-data__model` for `@ember-data/model` etc.
+* `@types/rsvp`
+* `@types/ember__test-helpers`
+
+## Files this addon generates
+
+We also add the following files to your project:
+
+* [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)
+* `types//index.d.ts` – the location for any global type declarations you need to write for you own application; see [**Using TS Effectively: Global types for your package**](https://github.com/typed-ember/ember-cli-typescript/tree/3a434def8b8c8214853cea0762940ccedb2256e8/docs/getting-started/docs/ts/using-ts-effectively/README.md#global-types-for-your-package) for information on its default contents and how to use it effectively
+* `app/config/environment.d.ts` – a basic set of types defined for the contents of the `config/environment.js` file in your app; see [Environment and configuration typings](installation.md#environment-and-configuration-typings) for details
+
diff --git a/docs/legacy/README.md b/docs/legacy/README.md
new file mode 100644
index 000000000..002bba826
--- /dev/null
+++ b/docs/legacy/README.md
@@ -0,0 +1,9 @@
+# Working With Ember Classic
+
+We emphasize the happy path of working with Ember in the [Octane Edition](https://emberjs.com/editions/octane/). However, there are times you’ll need to understand these details:
+
+1. Most existing applications make heavy use of the pre-Octane \(“legacy”\) Ember programming model, and we support that model—with caveats.
+2. Several parts of Ember Octane \(specifically: routes, controllers, services, and class-based helpers\) continue to use these concepts under the hood, and our types support that—so understanding them may be important at times.
+
+The rest of this guide is dedicated to helping you understand how `ember-cli-typescript` and the classic Ember system interact.
+
diff --git a/docs/legacy/computed-properties.md b/docs/legacy/computed-properties.md
new file mode 100644
index 000000000..79f01bae5
--- /dev/null
+++ b/docs/legacy/computed-properties.md
@@ -0,0 +1,72 @@
+# Computed Properties
+
+There are two variants of Ember’s computed properties you may encounter:
+
+* the decorator form used with native \(ES6\) classes
+* the callback form used with classic classes \(based on EmberObject\)
+
+## Decorator form
+
+```typescript
+import Component from '@ember/component';
+import { computed } from '@ember/object/computed';
+
+export default class UserProfile extends Compoennt {
+ name = 'Chris';
+ age = 33;
+
+ @computed('name', 'age')
+ get bio() {
+ return `${this.name} is `${this.age}` years old!`;
+ }
+}
+```
+
+Note that it is impossible for `@computed` to know whether the keys you pass to it are allowed or not. Migrating to Octane eliminates this issue, since you mark reactive root state with `@tracked` and leave getters undecorated, rather than vice versa.
+
+## Callback form
+
+Computed properties in the classic object model take a callback instead:
+
+```typescript
+import Component from '@ember/component';
+import { computed } from '@ember/object/computed';
+
+const UserProfile = Component.extend({
+ name: 'Chris',
+ age: 32,
+
+ bio: computed('name', 'age', function() {
+ return `${this.get('name')} is `${this.get('age')}` years old!`;
+ }),
+})
+
+export default UserProfile;
+```
+
+This definition will not type-check, however. You will need to explicitly write out a `this` type for computed property callbacks for `get` and `set` to type-check correctly:
+
+```typescript
+import Component from '@ember/component';
+import { computed } from '@ember/object/computed';
+
+const UserProfile = Component.extend({
+ name: 'Chris',
+ age: 32,
+
+ bio: computed('name', 'age', function(this: UserProfile) {
+ // ^---------------^
+ // `this` tells TS to use `UserProfile` for `get` and `set` lookups;
+ // otherwise `this.get` below would not know the types of `'name'` or
+ // `'age'` or even be able to suggest them for autocompletion.
+ return `${this.get('name')} is `${this.get('age')}` years old!`;
+ }),
+})
+
+export default UserProfile;
+```
+
+Note that this _does not always work_: you may get warnings from TypeScript about the item being defined in terms of itself.
+
+**Accordingly, we strongly recommend migrating classic classes to ES native classes** _**before**_ **adding TypeScript!**
+
diff --git a/docs/legacy/ember-component.md b/docs/legacy/ember-component.md
new file mode 100644
index 000000000..293f023ac
--- /dev/null
+++ b/docs/legacy/ember-component.md
@@ -0,0 +1,2 @@
+# EmberComponent
+
diff --git a/docs/legacy/ember-object.md b/docs/legacy/ember-object.md
new file mode 100644
index 000000000..ecbb82720
--- /dev/null
+++ b/docs/legacy/ember-object.md
@@ -0,0 +1,81 @@
+# EmberObject
+
+When working with the legacy Ember object model, `EmberObject`, there are a number of caveats and limitations you need to be aware of. For today, these caveats and limitations apply to any classes which extend directly from `EmberObject`, or which extend classes which _themselves_ extend `EmberObject`:
+
+* `Component` – meaning _classic_ Ember components, which imported from `@ember/component`, _not_ Glimmer components which are imported from `@glimmer/component` and do _not_ extend the `EmberObject` base class.
+* `Controller`
+* `Helper` – note that this applies only to the _class_ form. Function-based helpers do not involve the `EmberObject` base class.
+* `Route`
+* `Router`
+* `Service`
+* Ember Data’s `Model` class
+
+Additionally, Ember’s mixin system is deeply linked to the semantics and implementation details of `EmberObject`, _and_ it has the most caveats and limitations.
+
+{% hint style="info" %}
+In the future, some of these may be able to drop their `EmberObject` base class dependency, but that will not happen till at least the next major version of Ember, and these guides will be updated when that happens.
+{% endhint %}
+
+## Mixins and classic class syntax
+
+The Ember mixin system is the legacy Ember construct TypeScript supports _least_ well, as described in [Mixins](https://github.com/typed-ember/ember-cli-typescript/tree/3a434def8b8c8214853cea0762940ccedb2256e8/docs/legacy/mixins/README.md). While this may not be intuitively obvious, the classic class syntax simply _is_ the mixin system. Every classic class creation is a case of mixing together multiple objects to create a new base class with a shared prototype. The result is that any time you see the classic `.extend({ ... })` syntax, regardless of whether there is a named mixin involved, you are dealing with Ember's legacy mixin system. This in turn means that you are dealing with the parts of Ember which TypeScript is _least_ able to handle well.
+
+While we describe here how to use types with classic \(mixin-based\) classes insofar as they _do_ work, there are many failure modes. As a result, we strongly recommend moving away from both classic classes and mixins, and as quickly as possible. This is the direction the Ember ecosystem as a whole is moving, but it is _especially_ important for TypeScript users.
+
+{% hint style="info" %}
+The [Ember Atlas](https://emberatlas.com) includes guides for migrating [from classic classes to native classes](https://www.notion.so/Native-Classes-55bd67b580ca49f999660caf98aa1897), along with [a variety of patterns](https://www.notion.so/Converting-Classes-with-Mixins-5dc68c0ac3044e51a218fa7aec71c2db) for dealing with specific kinds of mixins in your codebase.
+{% endhint %}
+
+### Failure modes
+
+You often need to define `this` in actions hashes, computd properties, etc. That in turn often leads to problems with self-referential `this`: TypeScript simply cannot figure out how to stop recursing through the definitions of the type.
+
+Additionally, even when you get past the endlessly-recursive type definition problems, when enough mixins are resolved TypeScript will occasionally just give up because it cannot resolve the property or method you're interested in across the many shared base classes.
+
+Finally, when you have "zebra-striping" of your classes between classic classes and native classes, your types will often stop resolving.
+
+## Native classes
+
+### `EmberObject`
+
+In general, we recommend \(following the Ember Octane guides\) that any class which extends directly from the `EmberObject` base class eliminate any use of `EmberObject`-specific API and convert to standalone class, with no base class at all. You can follow the [ember-classic-decorator](https://github.com/emberjs/ember-classic-decorator) workflow to eliminate the base class—switching from `init` to `constructor`, getting rid of uses of methods like `this.set` and `this.get` in favor of using standalone `set` and `get`, and so on.
+
+### `EmberObject`-descended classes
+
+The framework base classes which depend on `EmberObject` cannot follow the exact same path. However, as long as you are using native class syntax, all of these \(`Component`, `Controller`, `Helper`, etc.\) work nicely and safely with TypeScript. In each of these cases, the same caveats apply as with `EmberObject` itself, and you should follow the [ember-classic-decorator](https://github.com/emberjs/ember-classic-decorator) workflow with them as well if you are converting an existing app or addon. However, because these base classes themselves descend from `EmberObject`, you will not be able to remove the base classes as you can with your _own_ classes which descend _directly_ from `EmberObject`. Instead, you will continue to extend from the Ember base classes:
+
+```typescript
+import Component from '@ember/component';
+export default class Profile extends Component {}
+```
+
+```typescript
+import Controller from '@ember/controller';
+export default class IndexController extends Controller {}
+```
+
+```typescript
+import Helper from '@ember/component/helper';
+export default class Localize extends Helper {}
+```
+
+```typescript
+import Route from '@ember/routing/route';
+export default class ApplicationRoute extends Route {}
+```
+
+```typescript
+import EmberRouter from '@ember/routing/router'
+export default class AppRouter extends EmberRouter {}
+```
+
+```typescript
+import Service from '@ember/service';
+export default class Session extends Service {}
+```
+
+```typescript
+import Model from '@ember-data/model';
+export default class User extends Model {}
+```
+
diff --git a/docs/legacy/mixins.md b/docs/legacy/mixins.md
new file mode 100644
index 000000000..d7e8512ba
--- /dev/null
+++ b/docs/legacy/mixins.md
@@ -0,0 +1,15 @@
+# Mixins
+
+Mixins are fundamentally hostile to robust typing with TypeScript. While you can supply types for them, you will regularly run into problems with self-referentiality in defining properties within the mixins.
+
+As a stopgap, you can refer to the type of a mixin using the `typeof` operator.
+
+In general, however, prefer to use one of the following four strategies for migrating _away_ from mixins before attempting to convert code which relies on them to TypeScript:
+
+1. For functionality which encapsulates DOM modification, rewrite as a custom modifier using [ember-modifier](https://github.com/emeber-modifier/ember-modifier).
+2. If the mixin is a way of supplying shared behavior \(not data\), extract it to utility functions, usually just living in module scope and imported and exported as needed.
+3. If the mixin is a way of supplying non-shared state which follows the lifecycle of a given object, replace it with a utility class instantiated in the owning class's `constructor` \(or `init` for legacy classes\).
+4. If the mixin is a way of supplying long-lived, shared state, replace it with a service and inject it where it was used before. This pattern is uncommon, but sometimes appears when mixing functionality into multiple controllers or services.
+
+You can also use inheritance and class decorators to accomplish some of the same semantics as mixins classically supplied. However, these patterns are more fragile and therefore not recommended.
+
diff --git a/docs/troubleshooting/README.md b/docs/troubleshooting/README.md
new file mode 100644
index 000000000..0fe71a6b7
--- /dev/null
+++ b/docs/troubleshooting/README.md
@@ -0,0 +1,7 @@
+# Troubleshooting
+
+Stuck with something? Hopefully one of the documents below can help. If not, file an issue on GitHub and we'll try to help you get it sorted (and it may end up in here).
+
+## Outline
+
+* [Conflicting Type Dependencies](./conflicting-types.md)
diff --git a/docs/troubleshooting/conflicting-types.md b/docs/troubleshooting/conflicting-types.md
new file mode 100644
index 000000000..c38c90057
--- /dev/null
+++ b/docs/troubleshooting/conflicting-types.md
@@ -0,0 +1,90 @@
+# Conflicting Type Dependencies
+
+You will sometimes see **Duplicate identifier** errors when type-checking your application.
+
+An example duplicate identifier error \`\`\`sh yarn tsc --noEmit yarn run v1.15.2 $ /Users/chris/dev/teaching/emberconf-2019/node\_modules/.bin/tsc --noEmit node\_modules/@types/ember\_\_object/index.d.ts:23:22 - error TS2300: Duplicate identifier 'EmberObject'. 23 export default class EmberObject extends CoreObject.extend\(Observable\) {} ~~~~~~~~~~~ node\_modules/@types/ember\_\_component/node\_modules/@types/ember\_\_object/index.d.ts:23:22 23 export default class EmberObject extends CoreObject.extend\(Observable\) {} ~~~~~~~~~~~ 'EmberObject' was also declared here. node\_modules/@types/ember\_\_component/node\_modules/@types/ember\_\_object/index.d.ts:23:22 - error TS2300: Duplicate identifier 'EmberObject'. 8 export default class EmberObject extends CoreObject.extend\(Observable\) {} ~~~~~~~~~~~ node\_modules/@types/ember\_\_object/index.d.ts:23:22 23 export default class EmberObject extends CoreObject.extend\(Observable\) {} ~~~~~~~~~~~ 'EmberObject' was also declared here. Found 2 errors. error Command failed with exit code 1. \`\`\`
+
+This occurs whenever your `yarn.lock` or `package-lock.json` files include more than a single copy of a given set of type definitions—here, types for `@ember/object`, named `@types/ember__object`. See below for details on the package manager behavior, and **Understanding the Package Names** for details on the package names.
+
+## Workarounds
+
+There are currently three recommended workarounds for this:
+
+* If using `npm`, you can use `npm upgrade --depth=1 @types/ember__object` to upgrade just that specific dependency and anywhere it is used as a transitive dependency of your top-level dependencies. You can also use its `npm dedupe` command, which may resolve the issue.
+* If using `yarn`, you can specify a specific version of the package to use in the `"resolutions"` key in `package.json`. For example, if you saw that you had `@types/ember__object@3.0.8` from the default package installs but `@types/ember__object@3.0.5` from `some-cool-ts-addon`, you could force yarn to use `3.0.8` like so:
+
+ ```javascript
+ {
+ "resolutions": {
+ "@types/ember__object": "3.0.8"
+ }
+ }
+ ```
+
+* You can identify the dependencies which installed the type dependencies transitively, and uninstall and reinstall them. For example, if running `yarn why` reported you had one version of `@types/ember__object` from [the normally-installed set of packages](https://github.com/typed-ember/ember-cli-typescript/tree/3a434def8b8c8214853cea0762940ccedb2256e8/docs/README.md#other-packages-this-addon-installs), and one from `some-cool-ts-addon`, you could run this:
+
+ ```bash
+ yarn remove @types/ember some-cool-ts-addon
+ yarn add -D @types/ember some-cool-ts-addon
+ ```
+
+You may _also_ be able to use [`yarn-deduplicate`](https://github.com/atlassian/yarn-deduplicate), but this does not work 100% of the time, so if you try it and are still seeing the issues, try one of the solutions above.
+
+## Understanding the Problem
+
+When you are using TypeScript in your Ember application, you consume Ember's types through [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped), the tool the TypeScript team built to power the `@types/*` definitions. That tooling examines the dependencies implied by the package imports and generates a `package.json` with those types specified with a `*` dependency version. On initial installation of your dependencies, yarn installs the highest version of the package available, and correctly deduplicates that across both your own package and all the `@types` packages which reference each other.
+
+However, later installs may introduce conflicting versions of the types, simply by way of yarn's normal update rules. TypeScript requires that there be one and only one type definition a given item can resolve to. Yarn actively avoids changing a previously-installed version of a transitive dependency when a newly installed package depends on the same dependency transitively. Thus, if one of your dependencies _also_ depends on the same package from `@types/*` that you do, and you upgrade your dependence on that type by editing your `package.json` file and running `yarn` or `npm install` again, TypeScript will suddenly start offering the error described in detail above:
+
+> Duplicate identifier 'EmberObject'.ts\(2300\)
+
+Let's imagine three packages, `A`, `B`, and `C`, where `A` is _your_ app or library, and `B` and `C` have the following versions and dependencies:
+
+* `C` is currently at version `1.2.3`.
+* `B` is at version `4.5.6`. It depends on `C` with a `*` dependency. So the `dependencies` key in its `package.json` looks like this:
+
+ ```javascript
+ {
+ "dependencies": {
+ "C": "*"
+ }
+ }
+ ```
+
+Now, you install _only_ `B` \(this is the equivalent of installing just the basic type definitions in your package\):
+
+```javascript
+{
+ "dependencies": {
+ "B": "~4.5.6"
+ }
+}
+```
+
+The first time you install these, you will get a _single_ version of `C` – `1.2.3`.
+
+Now, let's say that `C` publishes a new version, `1.2.4`, and `A` \(your app or library\) adds a dependency on both `C` like so:
+
+```javascript
+{
+ "dependencies": {
+ "B": "~4.5.6",
+ "C": "~1.2.0"
+ }
+}
+```
+
+When your package manager runs \(especially in the case of `yarn`\), it goes out of its way to leave the _existing_ installation of `C` in place, while adding a _new_ version for you as a top-level consumer. So now you have two versions of `C` installed in your `node_modules` directory: `1.2.3` \(for `B`\) and `1.2.4` \(for `A`, your app or library\).
+
+What's important to understand here is that this is _exactly_ the behavior you want as the default in the Node ecosystem. Automatically updating a transitive dependency—even when the change is simply a bug fix release—_can_ cause your entire app or library to stop working. If one of your dependencies accidentally depended on that buggy behavior, and adding a direct dependency on the fixed version caused the buggy version to be upgraded, you're just out of luck. Yarn accounts for this by resolving packages to the same version during initial installation, but leaving existing package resolutions as they are when adding new dependencies later.
+
+Unfortunately, this is also the _opposite_ of what you want for TypeScript, which needs a single source of truth for the types in your app or library. When you install the type definitions, and then _later_ install a package which transitively depends on those type definitions, you end up with multiple sources of truth for the types.
+
+## Understanding the Workarounds
+
+The solutions listed above both make sure npm apd Yarn only install a single version of the package.
+
+* Explicitly upgrading the dependencies or using `dedupe` resolves to a single version in npm.
+* Specifying a version in the `"resolutions"` field in your `package.json` simply forces Yarn to resolve _every_ reference to that package to a single version. This actually works extremely well for types, but it means that every time you either update the types package\(s\) yourself _or_ update a package which transitively depends on them, you have to edit this value manually as well.
+* Uninstalling and reinstalling both the impacted packages and _all_ the packages which transitively depend on them gives you the same behavior as an initial install… because that's exactly what you're doing. The downside, of course, is that you have to identify and uninstall and reinstall all top-level packages which transitively depend on the files, and this introduces risk by way of _other_ transitive dependencies being updated.
+
diff --git a/docs/ts/README.md b/docs/ts/README.md
new file mode 100644
index 000000000..8ad87c3b4
--- /dev/null
+++ b/docs/ts/README.md
@@ -0,0 +1,15 @@
+# TypeScript and Ember
+
+This guide covers the common details and "gotchas" of using TypeScript with Ember. Note that we do _not_ cover the use of TypeScript _or_ Ember in general—for those, you should refer to the corresponding documentation:
+
+* [TypeScript docs](https://www.typescriptlang.org/docs/index.html)
+* [TypeScript Deep Dive](https://basarat.gitbook.io/typescript/)
+* [Ember docs](https://emberjs.com/learn/)
+
+## Outline
+
+* [Using TypeScript With Ember Effectively](using-ts-effectively.md)
+* [Decorators](decorators.md)
+* [Current limitations](current-limitations.md)
+* [Building Addons in TypeScript](with-addons.md)
+* [Understanding the `@types` Package Names](package-names.md)
diff --git a/docs/ts/current-limitations.md b/docs/ts/current-limitations.md
new file mode 100644
index 000000000..60a94b109
--- /dev/null
+++ b/docs/ts/current-limitations.md
@@ -0,0 +1,61 @@
+# Current Limitations
+
+While TS already works nicely for many things in Ember, there are a number of corners where it _won't_ help you out. Some of them are just a matter of further work on updating the [existing typings](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember); others are a matter of further support landing in TypeScript itself, or changes to Ember's object model.
+
+## Some `import`s don't resolve
+
+You'll frequently see errors for imports which TypeScript doesn't know how to resolve. **These won't stop the build from working;** they just mean TypeScript doesn't know where to find those.
+
+Writing these missing type definitions is a great way to pitch in! Jump in `#e-typescript` on the [Ember Community Discord server](https://discord.gg/zT3asNS) and we'll be happy to help you.
+
+## Templates
+
+Templates are currently totally non-type-checked. This means that you lose any safety when moving into a template context, even if using a Glimmer `Component` in Ember Octane.
+
+Addons need to import templates from the associated `.hbs` file to bind to the layout of any components they export. The TypeScript compiler will report that it cannot resolve the module, since it does not know how to resolve files ending in `.hbs`. To resolve this, you can provide this set of definitions to `my-addon/types/global.d.ts`, which will allow the import to succeed:
+
+```ts
+declare module '\*/template' {
+ import { TemplateFactory } from 'htmlbars-inline-precompile';
+ const template: TemplateFactory; export default template;
+}
+
+
+declare module 'app/templates/\*' {
+ import { TemplateFactory } from 'htmlbars-inline-precompile';
+ const template: TemplateFactory; export default template;
+}
+
+declare module 'addon/templates/\*' {
+ import { TemplateFactory } from 'htmlbars-inline-precompile';
+ const template: TemplateFactory; export default template;
+}
+```
+
+## Invoking actions
+
+TypeScript won't detect a mismatch between this action and the corresponding call in the template:
+
+```ts
+import Component from '@ember/component';
+import { action } from '@ember/object';
+
+export default class MyGame extends Component {
+ @action turnWheel(degrees: number) {
+ // ...
+ }
+}
+```
+
+```hbs
+
+```
+
+Likewise, it won't notice a problem when you use the `send` method:
+
+```ts
+// TypeScript compiler won't detect this type mismatch
+this.send\('turnWheel', 'ALSO-NOT-A-NUMBER'\);
+```
diff --git a/docs/ts/decorators.md b/docs/ts/decorators.md
new file mode 100644
index 000000000..465569f58
--- /dev/null
+++ b/docs/ts/decorators.md
@@ -0,0 +1,21 @@
+# Decorators
+
+Ember makes heavy use of decorators, and TypeScript does not currently support deriving type information from decorators.
+
+As a result, there are three important points that apply to _all_ decorator usage in Ember:
+
+1. Whenever using a decorator to declare a class field the framework sets up for you, you should mark it with `declare`. That includes all service and controller injections as well as all Ember Data attributes and relationships.
+
+ Normally, TypeScript determines whether a property is definitely not `null` or `undefined` by checking what you do in the constructor. In the case of service injections, controller injections, or Ember Data model decorations, though, TypeScript does not have visibility into how instances of the class are _initialized_. The `declare` annotation informs TypeScript that something outside its
+
+2. For Ember Data Models, you will need to use the optional `?` operator on field declarations if the field is optional \(`?`\). See the Ember Data section of the guide for more details!
+
+3. You are responsible to write the type correctly. TypeScript does not currently use decorator information at all in its type information. If you write `@service foo` or even `@service('foo') foo`, _Ember_ knows that this resolves at runtime to the service `Foo`, but TypeScript does not and—for now—_cannot_.
+
+ This means that you are responsible to provide this type information, and that you are responsible to make sure that the information remains correct and up to date
+
+For examples, see the detailed discussions of the two main places decorators are used in the framework:
+
+* [Services](../ember/services.md)
+* [Ember Data Models](../ember-data/models.md)
+
diff --git a/docs/ts/package-names.md b/docs/ts/package-names.md
new file mode 100644
index 000000000..f161c0366
--- /dev/null
+++ b/docs/ts/package-names.md
@@ -0,0 +1,9 @@
+# Understanding the `@types` Package Names
+
+You may be wondering why the packages added to your `package.json` and described in [**Installation: Other packages this addon installs**](https://github.com/typed-ember/ember-cli-typescript/tree/3a434def8b8c8214853cea0762940ccedb2256e8/docs/README.md#other-packages-this-addon-installs) are named things like `@types/ember__object` instead of something like `@types/@ember/object`. This is a conventional name used to allow both the compiler and the [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) publishing infrastructure \([types-publisher](https://github.com/Microsoft/types-publisher)\) to handle scoped packages, documented under [**What about scoped packages?**](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master#what-about-scoped-packages) in [the DefinitelyTyped README](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master).
+
+See also:
+
+* [Microsoft/types-publisher\#155](https://github.com/Microsoft/types-publisher/issues/155)
+* [Microsoft/Typescript\#14819](https://github.com/Microsoft/TypeScript/issues/14819)
+
diff --git a/tests/dummy/app/templates/docs/ts-guide/using-ts-effectively.md b/docs/ts/using-ts-effectively.md
similarity index 51%
rename from tests/dummy/app/templates/docs/ts-guide/using-ts-effectively.md
rename to docs/ts/using-ts-effectively.md
index eac5dc03c..54257d954 100644
--- a/tests/dummy/app/templates/docs/ts-guide/using-ts-effectively.md
+++ b/docs/ts/using-ts-effectively.md
@@ -1,14 +1,17 @@
-# Using TypeScript with Ember effectively
+# Using TypeScript With Ember Effectively
## Incremental adoption
-If you are porting an existing app to TypeScript, you can install this addon and migrate your files incrementally by changing their extensions from `.js` to `.ts`. As TypeScript starts to find errors (and it usually does!), make sure to celebrate your wins – even if they're small! – with your team, especially if some people are not convinced yet. We would also love to hear your stories!
+If you are porting an existing app to TypeScript, you can install this addon and migrate your files incrementally by changing their extensions from `.js` to `.ts`. As TypeScript starts to find errors (and it usually does!), make sure to celebrate your wins—even if they're small!—with your team, especially if some people are not convinced yet. We would also love to hear your stories!
Some specific tips for success on the technical front:
-- Use the _strictest_ strictness settings that our typings allow. While it may be tempting to start with the _loosest_ strictness settings and then to tighten them down as you go, this will actually mean that "getting your app type-checking" will become a repeated process – getting it type-checking with every new strictness setting you enable! – rather than something you do just once. The only strictness setting you should turn _off_ is `strictFunctionTypes`, which our current type definitions do not support. The recommended _strictness_ settings in your `"compilerOptions"` hash:
+First, use the _strictest_ strictness settings that our typings allow (currently all strictness settings except `strictFunctionTypes`). While it may be tempting to start with the _loosest_ strictness settings and then to tighten them down as you go, this will actually mean that "getting your app type-checking" will become a repeated process—getting it type-checking with every new strictness setting you enable—rather than something you do just once.
- ```
+The full recommended _strictness_ settings in your `"compilerOptions"` hash:
+
+```json
+{
"noImplicitAny": true,
"noImplicitThis": true,
"alwaysStrict": true,
@@ -18,41 +21,39 @@ Some specific tips for success on the technical front:
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
- ```
-
-- A good approach is to start at your "leaf" files (the ones that don't import anything else from your app, only Ember types) and then work your way back inward toward the most core types that are used everywhere. Often the highest-value modules are your Ember Data models and any core services that are used everywhere else in the app – and those are also the ones that tend to have the most cascading effects (having to update _tons_ of other places in your app) when you type them later in the process.
+ "noUncheckedIndexedAccess": true,
+}
+```
-- Set `"noEmitOnError": true` in the `"compilerOptions"` hash in your `tsconfig.json` – it will help a lot if you can be sure that for the parts of your app you _have_ added types to are still correct. And you'll get nice feedback _immediately_ when you have type errors that way!
+A good approach is to start at your "leaf" files (the ones that don't import anything else from your app, only Ember types) and then work your way back inward toward the most core types that are used everywhere. Often the highest-value modules are your Ember Data models and any core services that are used everywhere else in the app – and those are also the ones that tend to have the most cascading effects (having to update _tons_ of other places in your app) when you type them later in the process.
- ![type errors in your build!](https://user-images.githubusercontent.com/108688/38774630-7d9224d4-403b-11e8-8dbc-87dad977a4c4.gif 'example of a build error during live reload')
+Finally, leave `"noEmitOnError": true` (the default) in the `"compilerOptions"` hash in your `tsconfig.json`. This will fail your build if you have type errors, which gives you the fastest feedback as you add types.
-- There are two schools of thought on how to handle things you don't have types for as you go:
+![example of a build error during live reload](https://user-images.githubusercontent.com/108688/38774630-7d9224d4-403b-11e8-8dbc-87dad977a4c4.gif)
- - Liberally use `any` for them and come back and fill them in later. This will let you do the strictest strictness settings but with an escape hatch that lets you say "We will come back to this when we have more idea how to handle it."
+## What about missing types?
- - Go more slowly, but write down at least minimally accurate types as you go. (This is easier if you follow the leaves-first strategy recommended above.) This is much harder, but allows you to have much higher confidence as you work through the app.
+There are two schools of thought on how to handle things you don't have types for as you go:
- There is an inherent tradeoff between these two approaches; which works best will depend on your team and your app.
+* Liberally use `any` for them and come back and fill them in later. This will let you do the strictest strictness settings but with an escape hatch that lets you say "We will come back to this when we have more idea how to handle it." This approach lets you move faster, but means you will still have lots of runtime type errors: `any` just turns the type-checker *off* for anything touching those modules. You’ll have to come back later and clean those up, and you’ll likely have more difficult refactorings to do at that time.
-You may find the blog series ["Typing Your Ember"][typing-your-ember] helpful as it walks you through not only how to install but how to most effectively use TypeScript in an Ember app today, and gives some important info on the background and roadmap for the project.
+* Go more slowly, but write down at least minimally accurate types as you go. (This is easier if you follow the leaves-first strategy recommended above.) This is much slower going, and can feel harder because you can’t just skip over things. Once you complete the work for any given module, though, you can be confident that everything is solid and you won’t have to revisit it in the future.
-[typing-your-ember]: http://www.chriskrycho.com/typing-your-ember.html
+There is an inherent tradeoff between these two approaches; which works best will depend on your team and your app.
## Install other types!
You'll want to use other type definitions as much as possible. The first thing you should do, for example, is install the types for your testing framework of choice: `@types/ember-mocha` or `@types/ember-qunit`. Beyond that, look for types from other addons: it will mean writing `any` a lot less and getting a lot more help both from your editor and from the compiler.
-*Where can I find types?* Some addons will ship them with their packages, and work out of the box. For others, you can search for them on [Definitely Typed], or on npm under the `@types` namespace. (In the future we hope to maintain a list of known types; keep your eyes open!)
-
-[Definitely Typed]: https://github.com/DefinitelyTyped/DefinitelyTyped
+_Where can I find types?_ Some addons will ship them with their packages, and work out of the box. For others, you can search for them on [Definitely Typed](https://github.com/DefinitelyTyped/DefinitelyTyped), or on npm under the `@types` namespace. (In the future we hope to maintain a list of known types; keep your eyes open!)
## The `types` directory
During installation, we create a `types` directory in the root of your application and add a `"paths"` mapping that includes that directory in any type lookups TypeScript tries to do. This is convenient for a few things:
-- global types for your package (see the next section)
-- writing types for third-party/`vendor` packages which do not have any types
-- developing types for an addon which you intend to upstream later
+* global types for your package (see the next section)
+* writing types for third-party/`vendor` packages which do not have any types
+* developing types for an addon which you intend to upstream later
These are all fallbacks, of course, you should use the types supplied directly with a package
@@ -60,9 +61,7 @@ These are all fallbacks, of course, you should use the types supplied directly w
At the root of your application or addon, we include a `types/` directory with an `index.d.ts` file in it. Anything which is part of your application but which must be declared globally can go in this file. For example, if you have data attached to the `Window` object when the page is loaded (for bootstrapping or whatever other reason), this is a good place to declare it.
-In the case of applications (but not for addons), we also automatically include declarations for Ember's prototype extensions in this `index.d.ts` file, with the `Array` prototype extensions enabled and the `Function` prototype extensions commented out. You should configure them to match your own config (which we cannot check during installation). If you are [disabling Ember's prototype extensions][disabling], you can remove these declarations entirely; we include them because they're enabled in most Ember applications today.
-
-[disabling]: https://guides.emberjs.com/v2.18.0/configuring-ember/disabling-prototype-extensions/
+In the case of applications (but not for addons), we also automatically include declarations for Ember's prototype extensions in this `index.d.ts` file, with the `Array` prototype extensions enabled and the `Function` prototype extensions commented out. You should configure them to match your own config (which we cannot check during installation). If you are [disabling Ember's prototype extensions](https://guides.emberjs.com/v2.18.0/configuring-ember/disabling-prototype-extensions/), you can remove these declarations entirely; we include them because they're enabled in most Ember applications today.
### Environment configuration typings
@@ -74,37 +73,8 @@ We install this file because the actual `config/environment.js` is (a) not actua
Ember makes heavy use of string-based APIs to allow for a high degree of dynamicism. With some limitations, you can nonetheless use TypeScript very effectively to get auto-complete/IntelliSense as well as to accurately type-check your applications.
-The "Update" sequence in the Typing Your Ember has detailed explanations and guides for getting good type-safety for Ember's string-based APIs, e.g. the use of `get` and `set`, service and controller injection, Ember Data models and lookups
-
-- [Part 1][pt1]: A look at normal Ember objects, "arguments" to components (and controllers), and service (or controller) injections.
-- [Part 2][pt2]: Class properties — some notes on how things differ from the `Ember.Object` world.
-- [Part 3][pt3]: Computed properties, actions, mixins, and class methods.
-- [Part 4][pt4]: Using Ember Data, and service and controller injections improvements. (This includes a detailed guide to updating making the service and controller injections and Ember Data lookups behave as described below.)
-
-[pt1]: http://www.chriskrycho.com/2018/typing-your-ember-update-part-1.html
-[pt2]: http://www.chriskrycho.com/2018/typing-your-ember-update-part-2.html
-[pt3]: http://www.chriskrycho.com/2018/typing-your-ember-update-part-3.html
-[pt4]: http://www.chriskrycho.com/2018/typing-your-ember-update-part-4.html
-
A few of the most common speed-bumps are listed here to help make this easier:
-### `this` type workaround
-
-One important note for using `class` types effectively with today's Ember typings: you will (at least for now) need to explicitly write out a `this` type for methods, computed property callbacks, and actions if you are going to use `get` or `set`
-
-```ts
-import Component from '@ember/component';
-
-export default class UserProfile extends Component {
- changeUsername(this: UserProfile, userName: string) {
- // ^---------------^
- // `this` tells TS to use `UserProfile` for `get` and `set` lookups
- }
-}
-```
-
-This is a workaround for how incredibly dynamic `Ember.Object` instances are and hopefully will improve over time as we continue to iterate on the type definitions. Again, see [the relevant blog post for details][pt2].
-
### Nested keys in `get` or `set`
In general, `this.get` and `this.set` will work as you'd expect _if_ you're doing lookups only a single layer deep. Things like `this.get('a.b.c')` don't (and can't ever!) type-check; see the blog posts for a more detailed discussion of why.
@@ -113,7 +83,7 @@ The workaround is simply to do one of two things:
1. **The type-safe approach.** This _will_ typecheck, but is both ugly and only works \*if there are no `null`s or `undefined`s along the way. If `nested` is `null` at runtime, this will crash!
- ```ts
+ ```typescript
import { get } from '@ember/object';
// -- Type-safe but ugly --//
@@ -122,7 +92,7 @@ The workaround is simply to do one of two things:
2. **Using `// @ts-ignore`.** This will _not do any type-checking_, but is useful for the cases where you are intentionally checking a path which may be `null` or `undefined` anywhere long it.
- ```ts
+ ```typescript
// @ts-ignore
get(someObject, 'deeply.nested.key');
```
@@ -133,9 +103,9 @@ The workaround is simply to do one of two things:
Ember does service and controller lookups with the `inject` functions at runtime, using the name of the service or controller being injected up as the default value—a clever bit of metaprogramming that makes for a nice developer experience. TypeScript cannot do this, because the name of the service or controller to inject isn't available at compile time in the same way.
-The officially supported method for injections with TypeScript uses *decorators*, from the ember-decorators package (and soon in Ember itself).
+The officially supported method for injections with TypeScript uses _decorators_.
-```ts
+```typescript
// my-app/services/my-session.ts
import Service from '@ember/service';
import RSVP from 'rsvp';
@@ -155,15 +125,15 @@ declare module '@ember/service' {
Then we can use the service as we usually would with a decorator, but adding a type annotation to it so TypeScript knows what it's looking at:
-```ts
+```typescript
// my-app/components/user-profile.ts
import Component from '@ember/component';
-import { service } from '@ember-decorators/service';
+import { inject as service } from '@ember/service';
import MySession from 'my-app/services/my-session';
export default class UserProfile extends Component {
- @service mySession!: MySession;
+ @service declare mySession: MySession;
login(email: string, password: string) {
this.mySession.login(email, password);
@@ -173,9 +143,9 @@ export default class UserProfile extends Component {
Note that we need the `MySession` type annotation this way, but we _don't_ need the string lookup (unless we're giving the service a different name than the usual on the class, as in Ember injections in general). Without the type annotation, the type of `session` would just be `any`. This is because decorators are not allowed to modify the types of whatever they decorate. As a result, we wouldn't get any type-checking on that `session.login` call, and we wouldn't get any auto-completion either. Which would be really sad and take away a lot of the reason we're using TypeScript in the first place!
-Also notice the [`!` non-null assertion operator](https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#non-null-assertion-operator), which is required to prevent [`TS2564`](https://github.com/kaorun343/vue-property-decorator/issues/81), that is caused by enabling `strictPropertyInitialization` in `tsconfig.json`.
+Also notice [the `declare` property modifier](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#the-usedefineforclassfields-flag-and-the-declare-property-modifier). This tells TypeScript that the property will be configured by something outside the class (in this case, the decorator), and guarantees it emits spec-compliant JavaScript.
-This also holds true for all other macros of the ember-decorators addon.
+(This also holds true for all other service injections, computed property macros, and Ember Data model attributes and relationships.)
### Earlier Ember versions
@@ -185,7 +155,7 @@ On Ember versions **earlier than 3.1**, you'll want to wrap your service type in
On Ember versions **earlier than 3.6**, you may encounter problems when providing type definitions like this:
-```ts
+```typescript
import Component from '@ember/component';
export default class UserProfile extends Component {
@@ -193,9 +163,9 @@ export default class UserProfile extends Component {
}
```
-When invoked via a template `{{user-profile username='example123'}}`, you would expect that `username` would have the value of `example123`, however prior to the native class feature released in Ember `3.6`, this will result in `username` being undefined.
+When invoked via a template `{{user-profile username='example123'}}`, you would expect that `username` would have the value of `example123`, however prior to the native class feature released in Ember `3.6`, this will result in `username` being undefined.
-For users who remain on Ember versions below `3.6`, please use https://github.com/pzuraq/ember-native-class-polyfill
+For users who remain on Ember versions below `3.6`, please use [https://github.com/pzuraq/ember-native-class-polyfill](https://github.com/pzuraq/ember-native-class-polyfill)
### Ember Data lookups
@@ -203,14 +173,12 @@ We use the same basic approach for Ember Data type lookups with string keys as w
The declarations and changes you need to add to your existing files are:
-- Models
+* Models
- ```ts
- import DS from 'ember-data';
+ ```typescript
+ import Model from '@ember-data/model';
- export default class UserMeta extends DS.Model.extend({
- // attribute declarations here, as usual
- }) {}
+ export default class UserMeta extends Model {}
declare module 'ember-data/types/registries/model' {
export default interface ModelRegistry {
@@ -219,14 +187,12 @@ The declarations and changes you need to add to your existing files are:
}
```
-- Adapters
+* Adapters
- ```ts
- import DS from 'ember-data';
+ ```typescript
+ import Adapter from '@ember-data/adapter';
- export default class UserMeta extends DS.Adapter {
- // properties and methods
- }
+ export default class UserMeta extends Adapter {}
declare module 'ember-data/types/registries/adapter' {
export default interface AdapterRegistry {
@@ -235,14 +201,12 @@ The declarations and changes you need to add to your existing files are:
}
```
-- Serializers
+* Serializers
- ```ts
- import DS from 'ember-data';
+ ```typescript
+ import Serializer from '@ember-data/serializer';
- export default class UserMeta extends DS.Serializer {
- // properties and methods
- }
+ export default class UserMeta extends Serializer {}
declare module 'ember-data/types/registries/serializer' {
export default interface SerializerRegistry {
@@ -251,14 +215,12 @@ The declarations and changes you need to add to your existing files are:
}
```
-- Transforms
+* Transforms
- ```ts
- import DS from 'ember-data';
+ ```typescript
+ import Transform from '@ember-data/serializer/transform';
- export default class ColorTransform extends DS.Transform {
- // properties and methods
- }
+ export default class ColorTransform extends Transform {}
declare module 'ember-data/types/registries/transform' {
export default interface TransformRegistry {
@@ -267,52 +229,50 @@ The declarations and changes you need to add to your existing files are:
}
```
-In addition to the registry, note the oddly defined class for `DS.Model`s. This is because we need to set up the attribute bindings on the prototype (for a discussion of how and why this is different from class properties, see [Typing Your Ember, Update, Part 2][pt2]), but we cannot just use a `const` here because we need a named type—like a class!—to reference in the type registry and elsewhere in the app.
-
-[pt2]: http://www.chriskrycho.com/2018/typing-your-ember-update-part-2.html
-
#### Opt-in unsafety
Also notice that unlike with service and controller injections, there is no unsafe fallback method by default, because there isn't an argument-less variant of the functions to use as there is for `Service` and `Controller` injection. If for some reason you want to opt _out_ of the full type-safe lookup for the strings you pass into methods like `findRecord`, `adapterFor`, and `serializerFor`, you can add these declarations somewhere in your project:
-```ts
-import DS from 'ember-data';
+```typescript
+import Model from '@ember-data/model';
+import Adapter from '@ember-data/adapter';
+import Serializer from '@ember-data/serializer';
declare module 'ember-data/types/registries/model' {
export default interface ModelRegistry {
- [key: string]: DS.Model;
+ [key: string]: Model;
}
}
declare module 'ember-data/types/registries/adapter' {
export default interface AdapterRegistry {
- [key: string]: DS.Adapter;
+ [key: string]: Adapter;
}
}
declare module 'ember-data/types/registries/serializer' {
export default interface SerializerRegistry {
- [key: string]: DS.Serializer;
+ [key: string]: Serializer;
}
}
```
-However, we **_strongly_** recommend that you simply take the time to add the few lines of declarations to each of your `DS.Model`, `DS.Adapter`, and `DS.Serializer` instances instead. It will save you time in even the short run!
+However, we _**strongly**_ recommend that you simply take the time to add the few lines of declarations to each of your `Model`, `Adapter`, and `Serializer` instances instead. It will save you time in even the short run!
#### Fixing the Ember Data `error TS2344` problem
If you're developing an Ember app or addon and _not_ using Ember Data (and accordingly not even have the Ember Data types installed), you may see an error like this and be confused:
-```
+```text
node_modules/@types/ember-data/index.d.ts(920,56): error TS2344: Type 'any' does not satisfy the constraint 'never'.
```
-This happens because the types for Ember's _test_ tooling includes the types for Ember Data because the `this` value in several of Ember's test types can include a reference to `DS.Store`.
+This happens because the types for Ember's _test_ tooling includes the types for Ember Data because the `this` value in several of Ember's test types can include a reference to the Ember Data `Store` class.
**The fix:** add a declaration like this in a new file named `ember-data.d.ts` in your `types` directory:
-```ts
+```typescript
declare module 'ember-data/types/registries/model' {
export default interface ModelRegistry {
- [key: string]: any;
+ [key: string]: unknown;
}
}
```
@@ -325,95 +285,9 @@ If you're developing an addon and concerned that this might affect consumers, it
Some common stumbling blocks for people switching to ES6 classes from the traditional EmberObject setup:
-- `Assertion Failed: InjectedProperties should be defined with the inject computed property macros.` – You've written `someService = inject()` in an ES6 class body in Ember 3.1+. Replace it with the `.extend` approach or by using decorators (`@service` or `@controller`) as discussed [above](#service-and-controller-injections). Because computed properties of all sorts, including injections, must be set up on a prototype, _not_ on an instance, if you try to use class properties to set up injections, computed properties, the action hash, and so on, you will see this error.
-
-- `Assertion Failed: Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.` – You failed to pass `...arguments` when you called `super` in e.g. a component class `constructor`. Always do `super(...arguments)`, not just `super()`, in your `constructor`.
+* `Assertion Failed: InjectedProperties should be defined with the inject computed property macros.` – You've written `someService = inject()` in an ES6 class body in Ember 3.1+. Replace it with the `.extend` approach or by using decorators\(`@service` or `@controller`) as discussed [above](using-ts-effectively.md#service-and-controller-injections). Because computed properties of all sorts, including injections, must be set up on a prototype, _not_ on an instance, if you try to use class properties to set up injections, computed properties, the action hash, and so on, you will see this error.
+* `Assertion Failed: Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.` – You failed to pass `...arguments` when you called `super` in e.g. a component class `constructor`. Always do `super(...arguments)`, not just `super()`, in your `constructor`.
## Type definitions outside `node_modules/@types`
-By default, the TypeScript compiler loads all type definitions found in `node_modules/@types`. If the type defs you need are not found there and are not supplied in the root of the package you're referencing, you can register a custom value in `paths` in the `tsconfig.json` file. For example, if you're using [ember-browserify], you're used to writing imports like this:
-
-[ember-browserify]: https://github.com/ef4/ember-browserify
-
-```js
-import MyModule from 'npm:my-module';
-```
-
-If `my-module` has types, you will not be able to resolve them this way by default. You can add a simple tweak to your `tsconfig.json` to resolve the types correctly, however, mapping `npm:*` to `node_modules/*`.
-
-```json
-{
- "compilerOptions": {
- "paths": {
- "my-app-name/*": ["app/*"],
- "npm:*": ["node_modules/*"]
- }
- }
-}
-```
-
-## ember-cli-mirage
-
-Mirage adds files from a nonstandard location to your application tree, so you'll need to tell the TypeScript compiler about how that layout works.
-
-For an app, this should look roughly like:
-
-```js
-{
- "compilerOptions": {
- "paths": {
- // ...
- "my-app-name/mirage/*": "mirage/*",
- }
- },
- "include": [
- "app",
- "tests",
- "mirage"
- ]
-}
-```
-
-And for an addon:
-
-```js
-{
- "compilerOptions": {
- "paths": {
- // ...
- "dummy/mirage/*": "tests/dummy/mirage/*",
- }
- },
- "include": [
- "addon",
- "tests"
- ]
-}
-```
-
-Note that if Mirage was present when you installed ember-cli-typescript (or if you run `ember g ember-cli-typescript`), this configuration should be automatically set up for you.
-
-## "TypeScript is complaining about multiple copies of the same types!"
-
-You may sometimes see TypeScript errors indicating that you have duplicate type definitions for Ember, Ember Data, etc. This is usually the result of an annoying quirk of the way both npm and yarn resolve your dependencies in their lockfiles.
-
-### Just tell me how to fix it
-
-There are two options here, neither of them _great_:
-
-- manually edit `yarn.lock` or `package-lock.json` and merge the conflicting
-- add a ["resolutions"] key to your `package.json` with the version you want to install of the types you're installing:
-
-```json
-{
- "resolutions": {
- "**/@types/ember": "2.8.15"
- }
-}
-```
-
-["resolutions"]: https://yarnpkg.com/lang/en/docs/selective-version-resolutions/
-
-### Why is this happening?
-
-If you're using another package which includes these types, and then you trigger an upgrade for your own copy of the type definitions, npm and yarn will both try to preserve the existing installation and simply add a new one for your updated version. In most cases, this is sane behavior, because it prevents transitive dependency breakage hell. However, in the _specific_ case of type definitions, it causes TypeScript to get confused.
+By default, the TypeScript compiler loads all type definitions found in `node_modules/@types`. If the type defs you need are not found there and are not supplied in the root of the package you're referencing, you can register a custom value in `paths` in the `tsconfig.json` file. See the [tsconfig.json docs](http://www.typescriptlang.org/docs/handbook/compiler-options.html#compiler-options) for details.
diff --git a/tests/dummy/app/templates/docs/ts-guide/with-addons.md b/docs/ts/with-addons.md
similarity index 88%
rename from tests/dummy/app/templates/docs/ts-guide/with-addons.md
rename to docs/ts/with-addons.md
index 3bdcb63dd..029193789 100644
--- a/tests/dummy/app/templates/docs/ts-guide/with-addons.md
+++ b/docs/ts/with-addons.md
@@ -4,10 +4,10 @@ Building addons in TypeScript offers many of the same benefits as building apps
## Key Differences from Apps
-To process `.ts` files, `ember-cli-typescript` [registers a set of Babel plugins](https://devblogs.microsoft.com/typescript/typescript-and-babel-7/) so that Babel knows how to strip away TypeScript-specific syntax. This means that `ember-cli-typescript` operates according to the same set of rules as other preprocessors when used by other addons.
+To process `.ts` files, `ember-cli-typescript` tells Ember CLI to [register a set of Babel plugins](https://devblogs.microsoft.com/typescript/typescript-and-babel-7/) so that Babel knows how to strip away TypeScript-specific syntax. This means that `ember-cli-typescript` operates according to the same set of rules as other preprocessors when used by other addons.
- - Like other addons that preprocess source files, **`ember-cli-typescript` must be in your addon's `dependencies`, not `devDependencies`**.
- - Because addons have no control over how files in `app/` are transpiled, **you cannot have `.ts` files in your addon's `app/` folder**.
+* Like other addons that preprocess source files, **`ember-cli-typescript` must be in your addon's `dependencies`, not `devDependencies`**.
+* Because addons have no control over how files in `app/` are transpiled, **you cannot have `.ts` files in your addon's `app/` folder**.
## Publishing
@@ -32,7 +32,8 @@ When you do this for a TypeScript addon, the source files will be picked up in t
You could run `ember ts:precompile` in your addon any time you change a file, but for development a simpler option is to temporarily update the `paths` configuration in the host application so that it knows how to resolve types from your linked addon.
Add entries for `` and `/*` in your `tsconfig.json` like so:
-```js
+
+```javascript
compilerOptions: {
// ...other options
paths: {
@@ -55,7 +56,7 @@ compilerOptions: {
Note that the `in-repo-addon` blueprint should automatically add these entries if you have `ember-cli-typescript-blueprints` installed when you run it.
-```js
+```javascript
compilerOptions: {
// ...other options
paths: {
diff --git a/docs/upgrade-notes.md b/docs/upgrade-notes.md
new file mode 100644
index 000000000..a631795fe
--- /dev/null
+++ b/docs/upgrade-notes.md
@@ -0,0 +1,166 @@
+# Upgrading from 1.x
+
+There are a number of important changes between ember-cli-typescript v1 and v2, which mean the upgrade process is _straightforward_ but _specific_:
+
+1. Update ember-cli-babel. Fix any problems introduced during the upgrade.
+2. Update ember-decorators. Fix any problems introduced during the upgrade.
+3. Update ember-cli-typescript. Follow the detailed upgrade guide below to fix discrepancies between Babel and TypeScript's compiled output.
+
+If you deviate from this order, you are likely to have a _much_ more difficult time upgrading!
+
+## Update ember-cli-babel
+
+ember-cli-typescript **requires** ember-cli-babel at version 7.1.0 or above, which requires ember-cli 2.13 or above. It also **requires** @babel/core 7.2.0 or higher.
+
+The recommended approach here is to deduplicate existing installations of the dependency, remove and reinstall ember-cli-babel to make sure that all its transitive dependencies are updated to the latest possible, and then to deduplicate _again_.
+
+If using yarn:
+
+```bash
+npx yarn-deduplicate
+yarn remove ember-cli-babel
+yarn add --dev ember-cli-babel
+npx yarn-deduplicate
+```
+
+If using npm:
+
+```bash
+npm dedupe
+npm uninstall ember-cli-babel
+npm install --save-dev ember-cli-babel
+npm dedupe
+```
+
+Note: If you are also using ember-decorators—and specifically the babel-transform that gets added with it—you will need update @ember-decorators/babel-transforms as well \(anything over 3.1.0 should work\):
+
+```bash
+ember install ember-decorators@^3.1.0 @ember-decorators/babel-transforms@^3.1.0
+```
+
+## Update ember-decorators
+
+If you're on a version of Ember before 3.10, follow the same process of deduplication, reinstallation, and re-deduplication as described for ember-cli-babel above for ember-decorators. This will get you the latest version of ember-decorators and, importantly, its @ember-decorators/babel-transforms dependency.
+
+## Update ember-cli-typescript
+
+Now you can simply `ember install` the dependency like normal:
+
+```bash
+ember install ember-cli-typescript@latest
+```
+
+_**Note:**_ **To work properly, starting from v2, ember-cli-typescript must be declared as a `dependency`, not a `devDependency` for addons. With `ember install` this migration would be automatically handled for you.**
+
+If you choose to make the upgrade manually with yarn or npm, here are the steps you need to follow:
+
+1. Remove ember-cli-typescript from your `devDependencies`.
+
+ With yarn:
+
+ ```bash
+ yarn remove ember-cli-typescript
+ ```
+
+ With npm:
+
+ ```bash
+ npm uninstall ember-cli-typescript
+ ```
+
+2. Install the latest of ember-cli-typescript as a `dependency`:
+
+ With yarn:
+
+ ```bash
+ yarn add ember-cli-typescript@latest
+ ```
+
+ With npm:
+
+ ```bash
+ npm install --save ember-cli-typescript@latest
+ ```
+
+3. Run `ember generate`:
+
+ ```bash
+ ember generate ember-cli-typescript
+ ```
+
+### Account for addon build pipeline changes
+
+Since we now integrate in a more traditional way into Ember CLI's build pipeline, there are two changes required for addons using TypeScript.
+
+* Addons can no longer use `.ts` in `app`, because an addon's `app` directory gets merged with and uses the _host's_ \(i.e. the other addon or app's\) preprocessors, and we cannot guarantee the host has TS support. Note that `.ts` will continue to work for in-repo addons because the app build works with the host's \(i.e. the app's, not the addon's\) preprocessors.
+* Similarly, apps must use `.js` to override addon defaults in `app`, since the different file extension means apps no long consistently "win" over addon versions \(a limitation of how Babel + app merging interact\).
+
+### Account for TS → Babel issues
+
+ember-cli-typescript v2 uses Babel to compile your code, and the TypeScript compiler only to _check_ your code. This makes for much faster builds, and eliminates the differences between Babel and TypeScript in the build output that could cause problems in v1. However, because of those differences, you’ll need to make a few changes in the process of upgrading.
+
+Any place where a type annotation overrides a _getter_
+
+* Fields like `element`, `disabled`, etc. as annotated defined on a subclass of `Component` and \(correctly\) not initialized to anything, e.g.:
+
+ ```typescript
+ import Component from '@ember/component';
+
+ export default class Person extends Component {
+ element!: HTMLImageElement;
+ }
+ ```
+
+ This breaks because `element` is a getter on `Component`. This declaration then shadows the getter declaration on the base class and stomps it to `undefined` \(effectively `Object.defineProperty(this, 'element', void 0)`. \(It would be nice to use `declare` here, but that doesn't work: you cannot use `declare` with a getter in a concrete subclass.\)
+
+ Two solutions:
+
+ 1. Annotate locally \(slightly more annoying, but less likely to troll you\):
+
+ ```typescript
+ class Image extends Component {
+ useElement() {
+ let element = this.element as HTMLImageElement;
+ console.log(element.src);
+ }
+ }
+ ```
+
+ 2. Use a local getter:
+
+ ```typescript
+ class Image extends Component {
+ // We do this because...
+ get _element(): HTMLImageElement {
+ return this.element as HTMLImageElement;
+ }
+
+ useElement() {
+ console.log(this._element.src);
+ }
+ }
+ ```
+
+ Notably, this is not a problem for Glimmer components, so migrating to Octane will also help!
+
+* `const enum` is not supported at all. You will need to replace all uses of `const enum` with simply `enum` or constants.
+* Using ES5 getters or settings with `this` type annotations is not supported through at least Babel 7.3. However, they should also be unnecessary with ES6 classes, so you can simply _remove_ the `this` type annotation.
+* Trailing commas after rest function parameters \(`function foo(...bar[],) {}`\) are disallowed by the ECMAScript spec, so Babel also disallows them.
+* Re-exports of types have to be disambiguated to be _types_, rather than values. Neither of these will work:
+
+ ```typescript
+ export { FooType } from 'foo';
+ ```
+
+ ```typescript
+ import { FooType } from 'foo';
+ export { FooType };
+ ```
+
+ In both cases, Babel attempts to emit a _value_ export, not just a _type_ export, and fails because there is no actual value to emit. You can do this instead as a workaround:
+
+ ```typescript
+ import * as Foo from 'foo';
+ export type FooType = Foo.FooType;
+ ```
+
diff --git a/package.json b/package.json
index 1fe9ce43b..183a5b90c 100644
--- a/package.json
+++ b/package.json
@@ -54,6 +54,8 @@
"@commitlint/cli": "11.0.0",
"@commitlint/config-conventional": "11.0.0",
"@ember/optional-features": "2.0.0",
+ "@glimmer/component": "^1.0.0-beta.3",
+ "@glimmer/tracking": "^1.0.0-beta.3",
"@typed-ember/renovate-config": "1.2.1",
"@types/capture-console": "1.0.0",
"@types/chai": "4.2.14",
@@ -63,6 +65,7 @@
"@types/debug": "4.1.5",
"@types/ember": "3.16.2",
"@types/ember-qunit": "3.4.13",
+ "@types/ember__object": "^3.1.1",
"@types/esprima": "4.0.2",
"@types/express": "4.17.7",
"@types/fs-extra": "9.0.4",
@@ -82,16 +85,10 @@
"commitlint-azure-pipelines-cli": "1.0.3",
"conventional-changelog-cli": "2.1.1",
"ember-cli": "3.22.0",
- "ember-cli-addon-docs": "ember-learn/ember-cli-addon-docs#4f5bfd11",
- "ember-cli-addon-docs-esdoc": "0.2.3",
"ember-cli-app-version": "4.0.0",
"ember-cli-babel": "7.23.0",
"ember-cli-blueprint-test-helpers": "0.19.2",
"ember-cli-dependency-checker": "3.2.0",
- "ember-cli-deploy": "1.0.2",
- "ember-cli-deploy-build": "2.0.0",
- "ember-cli-deploy-git": "1.3.4",
- "ember-cli-deploy-git-ci": "1.0.1",
"ember-cli-htmlbars": "5.3.1",
"ember-cli-inject-live-reload": "2.0.2",
"ember-cli-sri": "2.1.1",
diff --git a/tests/dummy/app/lib/generate-avatar.ts b/tests/dummy/app/lib/generate-avatar.ts
new file mode 100644
index 000000000..c755b9a4c
--- /dev/null
+++ b/tests/dummy/app/lib/generate-avatar.ts
@@ -0,0 +1,4 @@
+/** This exists just to support example code. */
+export function generateUrl(): string {
+ return '';
+}
diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js
index 76d7cae56..a44f39d47 100644
--- a/tests/dummy/app/router.js
+++ b/tests/dummy/app/router.js
@@ -1,27 +1,11 @@
-import AddonDocsRouter, { docsRoute } from 'ember-cli-addon-docs/router';
+import EmberRouter from '@ember/routing/router';
import config from './config/environment';
-const Router = AddonDocsRouter.extend({
+const Router = EmberRouter.extend({
location: config.locationType,
rootURL: config.rootURL,
});
-Router.map(function () {
- docsRoute(this, function () {
- this.route('upgrade-notes');
- this.route('configuration');
- this.route('ts-guide', function () {
- this.route('with-addons');
- this.route('using-ts-effectively');
- this.route('current-limitations');
- });
- this.route('troubleshooting', function () {
- this.route('conflicting-types');
- });
- this.route('type-defs', function () {
- this.route('package-names');
- });
- });
-});
+Router.map(function () {});
export default Router;
diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs
deleted file mode 100644
index c24cd6895..000000000
--- a/tests/dummy/app/templates/application.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{outlet}}
diff --git a/tests/dummy/app/templates/components/index-content.md b/tests/dummy/app/templates/components/index-content.md
deleted file mode 100644
index 4be54b8ce..000000000
--- a/tests/dummy/app/templates/components/index-content.md
+++ /dev/null
@@ -1,15 +0,0 @@
-## Why TypeScript?
-
-
-
-What is TypeScript, and why should you adopt it?
-
-> TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
-> —[typescriptlang.org](http://www.typescriptlang.org)
-
-TypeScript lets you build *ambitious web applications* with confidence—so it’s a perfect fit for Ember apps!
-
-- Get rid of `undefined is not a function` and `null is not an object` once and for all.
-- Enjoy API docs… that are always up-to-date.
-- Experience better developer productivity through top-notch editor support, including incredible autocomplete, guided refactorings, automatic imports, and more.
-
diff --git a/tests/dummy/app/templates/docs.hbs b/tests/dummy/app/templates/docs.hbs
deleted file mode 100644
index a671f5619..000000000
--- a/tests/dummy/app/templates/docs.hbs
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-{{#docs-viewer as |viewer|}}
-
- {{nav.section 'Introduction'}}
- {{nav.item 'Installation' 'docs.index'}}
- {{nav.item 'Upgrading from 1.x' 'docs.upgrade-notes'}}
- {{nav.item 'Configuration' 'docs.configuration'}}
-
- {{nav.section 'Using TypeScript with Ember'}}
- {{nav.item 'Using TypeScript Effectively' 'docs.ts-guide.using-ts-effectively'}}
- {{nav.item 'Building Addons in TypeScript' 'docs.ts-guide.with-addons'}}
- {{nav.item 'Current Limitations' 'docs.ts-guide.current-limitations'}}
-
- {{nav.section 'Working With Type Definition Files'}}
- {{nav.item 'Understanding the Package Names' 'docs.type-defs.package-names'}}
-
- {{nav.section 'Troubleshooting'}}
- {{nav.item 'Conflicting Type Dependencies' 'docs.troubleshooting.conflicting-types'}}
-
-
-
- {{outlet}}
-
-{{/docs-viewer}}
diff --git a/tests/dummy/app/templates/docs/index.md b/tests/dummy/app/templates/docs/index.md
deleted file mode 100644
index 477d3f237..000000000
--- a/tests/dummy/app/templates/docs/index.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Installation
-
-You can simply `ember install` the dependency like normal:
-
-```sh
-ember install ember-cli-typescript@latest
-```
-
-All dependencies will be added to your `package.json`, and you're ready to roll! **If you're upgrading from a previous release, see below!** you should check to merge any tweaks you've made to `tsconfig.json`.
-
-## Installation Results
-
-Installing ember-cli-typescript modifies your project in two ways:
-
-- installing a number of other packages to make TypeScript work in your app or addon
-- generating a number of files in your project
-
-### Other packages this addon installs
-
-We install the following packages—all at their current "latest" value—or generated:
-
-- [`typescript`](https://github.com/Microsoft/TypeScript)
-- **@types/ember** ([npm](https://www.npmjs.com/package/@types/ember) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember)) - Types for [Ember.js](https://github.com/emberjs/ember.js) which includes
- - **@types/ember\_\_string** ([npm](https://www.npmjs.com/package/@types/ember__string) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__string)) - types for the [`@ember/string` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fstring)
- - **@types/ember\_\_object** ([npm](https://www.npmjs.com/package/@types/ember__object) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__object)) - types for the [`@ember/object` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fobject)
- - **@types/ember\_\_utils** ([npm](https://www.npmjs.com/package/@types/ember__utils) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__utils)) - types for the [`@ember/utils` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Futils)
- - **@types/ember\_\_array** ([npm](https://www.npmjs.com/package/@types/ember__array) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__array)) - types for the [`@ember/array` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Farray)
- - **@types/ember\_\_component** ([npm](https://www.npmjs.com/package/@types/ember__component) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__component)) - types for the [`@ember/component` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fcomponent)
- - **@types/ember\_\_engine** ([npm](https://www.npmjs.com/package/@types/ember__engine) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__engine)) - types for the [`@ember/engine` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fengine)
- - **@types/ember\_\_application** ([npm](https://www.npmjs.com/package/@types/ember__application) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__application)) - types for the [`@ember/application` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fapplication)
- - **@types/ember\_\_controller** ([npm](https://www.npmjs.com/package/@types/ember__controller) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__controller)) - types for the [`@ember/controller` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fcontroller)
- - **@types/ember\_\_service** ([npm](https://www.npmjs.com/package/@types/ember__service) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__service)) - types for the [`@ember/service` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fservice)
- - **@types/ember\_\_runloop** ([npm](https://www.npmjs.com/package/@types/ember__runloop) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__runloop)) - types for the [`@ember/runloop` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Frunloop)
- - **@types/ember\_\_error** ([npm](https://www.npmjs.com/package/@types/ember__error) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__error)) - types for the [`@ember/error` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Ferror)
- - **@types/ember\_\_polyfills** ([npm](https://www.npmjs.com/package/@types/ember__polyfills) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__polyfills)) - types for the [`@ember/polyfills` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fpolyfills)
- - **@types/ember\_\_debug** ([npm](https://www.npmjs.com/package/@types/ember__debug) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__debug)) - types for the [`@ember/debug` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Fdebug)
- - **@types/ember\_\_test** ([npm](https://www.npmjs.com/package/@types/ember__test) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__test)) - types for the [`@ember/test` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Ftest)
- - **@types/ember\_\_routing** ([npm](https://www.npmjs.com/package/@types/ember__routing) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__routing)) - types for the [`@ember/routing` package](https://www.emberjs.com/api/ember/3.4/modules/@ember%2Frouting)
-- **@types/ember-data** - ([npm](https://www.npmjs.com/package/@types/ember-data) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember-data)) - Types for [Ember-Data](https://github.com/emberjs/data)
-- **@types/rsvp** - ([npm](https://www.npmjs.com/package/@types/rsvp) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/rsvp)) - Types for [RSVP.js](https://github.com/tildeio/rsvp.js/)
-- **@types/ember\_\_test-helpers** - ([npm](https://www.npmjs.com/package/@types/ember__test-helpers) | [source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember__test-helpers)) – Types for [@ember/test-helpers](https://github.com/emberjs/ember-test-helpers).
-
-### Files this addon generates
-
-We add the following files to your project:
-
-- [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)
-- `types//index.d.ts` – the location for any global type declarations you need to write for you own application; see [**Using TS Effectively: Global types for your package**](./docs/ts-guide/using-ts-effectively#global-types-for-your-package) for information on its default contents and how to use it effectively
-- `app/config/environment.d.ts` – a basic set of types defined for the contents of the `config/environment.js` file in your app; see [Environment and configuration typings](#environment-and-configuration-typings) for details
diff --git a/tests/dummy/app/templates/docs/troubleshooting/conflicting-types.md b/tests/dummy/app/templates/docs/troubleshooting/conflicting-types.md
deleted file mode 100644
index 919e03e2a..000000000
--- a/tests/dummy/app/templates/docs/troubleshooting/conflicting-types.md
+++ /dev/null
@@ -1,124 +0,0 @@
-# Conflicting Type Dependencies
-
-You will sometimes see Duplicate identifier errors when type-checking your application.
-
-An example duplicate identifier error
-
-```sh
-yarn tsc --noEmit
-yarn run v1.15.2
-$ /Users/chris/dev/teaching/emberconf-2019/node_modules/.bin/tsc --noEmit
-node_modules/@types/ember__object/index.d.ts:23:22 - error TS2300: Duplicate identifier 'EmberObject'.
-
-23 export default class EmberObject extends CoreObject.extend(Observable) {}
- ~~~~~~~~~~~
-
- node_modules/@types/ember__component/node_modules/@types/ember__object/index.d.ts:23:22
- 23 export default class EmberObject extends CoreObject.extend(Observable) {}
- ~~~~~~~~~~~
- 'EmberObject' was also declared here.
-
-node_modules/@types/ember__component/node_modules/@types/ember__object/index.d.ts:23:22 - error TS2300: Duplicate identifier 'EmberObject'.
-
-8 export default class EmberObject extends CoreObject.extend(Observable) {}
- ~~~~~~~~~~~
-
- node_modules/@types/ember__object/index.d.ts:23:22
- 23 export default class EmberObject extends CoreObject.extend(Observable) {}
- ~~~~~~~~~~~
- 'EmberObject' was also declared here.
-
-
-Found 2 errors.
-
-error Command failed with exit code 1.
-```
-
-
-
-This occurs whenever your `yarn.lock` or `package-lock.json` files include more than a single copy of a given set of type definitions—here, types for `@ember/object`, named `@types/ember__object`. See below for details on the yarn behavior, and {{#link-to 'docs.type-defs.package-names'}}Understanding the Package Names{{/link-to}} for details on the package names.
-
-## Workarounds
-
-There are currently two recommended workarounds for this:
-
-- You can specify a specific version of the package to use in the `"resolutions"` key in `package.json`. For example, if you saw that you had `@types/ember__object@3.0.8` from the default package installs but `@types/ember__object@3.0.5` from `some-cool-ts-addon`, you could force yarn to use `3.0.8` like so:
-
- ```json
- {
- "resolutions": {
- "@types/ember__object": "3.0.8"
- }
- }
- ```
-
-- You can identify the dependencies which installed the type dependencies transitively, and uninstall and reinstall them. For example, if running `yarn why` reported you had one version of `@types/ember__object` from [the normally-installed set of packages][default packages], and one from `some-cool-ts-addon`, you could run this:
-
- ```sh
- yarn remove @types/ember some-cool-ts-addon
- yarn add -D @types/ember some-cool-ts-addon
- ```
-
-[default packages]: ../../docs#other-packages-this-addon-installs
-
-## Understanding the Problem
-
-When you are using TypeScript in your Ember application, you consume Ember's types through [DefinitelyTyped], the tool the TypeScript team built to power the `@types/*` definitions. That tooling examines the dependencies implied by the package imports and generates a `package.json` with those types specified with a `*` dependency version. On initial installation of your dependencies, yarn installs the highest version of the package available, and correctly deduplicates that across both your own package and all the `@types` packages which reference each other.
-
-[DefinitelyTyped]: https://github.com/DefinitelyTyped/DefinitelyTyped
-
-However, later installs may introduce conflicting versions of the types, simply by way of yarn's normal update rules. TypeScript requires that there be one and only one type definition a given item can resolve to. Yarn actively avoids changing a previously-installed version of a transitive dependency when a newly installed package depends on the same dependency transitively. Thus, if one of your dependencies *also* depends on the same package from `@types/*` that you do, and you upgrade your dependence on that type by editing your `package.json` file and running `yarn` again, TypeScript will suddenly start offering the error described in detail above:
-
-> Duplicate identifier 'EmberObject'.ts(2300)
-
-Normally, running `yarn upgrade @types/ember__object` instead of updating your `package.json` file will resolve this for you, because yarn will deduplicate the packages once again. ::TODO: confirm this is accurate!::
-
-Let's imagine three packages, `A`, `B`, and `C`, where `A` is *your* app or library, and `B` and `C` have the following versions and dependencies:
-
-- `C` is currently at version `1.2.3`.
-- `B` is at version `4.5.6`. It depends on `C` with a `*` dependency. So the `dependencies` key in its `package.json` looks like this:
-
- ```json
- {
- "dependencies": {
- "C": "*"
- }
- }
- ```
-
-Now, you install *only* `B` (this is the equivalent of installing just the basic type definitions in your package):
-
-```json
-{
- "dependencies": {
- "B": "~4.5.6"
- }
-}
-```
-
-The first time you install these, you will get a *single* version of `C` – `1.2.3`.
-
-Now, let's say that `C` publishes a new version, `1.2.4`, and `A` (your app or library) adds a dependency on both `C` like so:
-
-```json
-{
- "dependencies": {
- "B": "~4.5.6",
- "C": "~1.2.0"
- }
-}
-```
-
-When yarn runs, it goes out of its way to leave the *existing* installation of `C` in place, while adding a *new* version for you as a top-level consumer. So now you have two versions of `C` installed in your `node_modules` directory: `1.2.3` (for `B`) and `1.2.4` (for `A`, your app or library).
-
-What's important to understand here is that this is *exactly* the behavior you want as the default in the Node ecosystem. Automatically updating a transitive dependency—even when the change is simply a bug fix release—*can* cause your entire app or library to stop working. If one of your dependencies accidentally depended on that buggy behavior, and adding a direct dependency on the fixed version caused the buggy version to be upgraded, you're just out of luck. Yarn accounts for this by resolving packages to the same version during initial installation, but leaving existing package resolutions as they are when adding new dependencies later.
-
-Unfortunately, this is also the *opposite* of what you want for TypeScript, which needs a single source of truth for the types in your app or library. When you install the type definitions, and then *later* install a package which transitively depends on those type definitions
-
-## Understanding the Workarounds
-
-The two solutions listed above both make sure Yarn only installs a single version of the package.
-
-- Specifying a version in the `"resolutions"` field in your `package.json` simply forces Yarn to resolve *every* reference to that package to a single version. This actually works extremely well for types, but it means that every time you either update the types package(s) yourself *or* update a package which transitively depends on them, you have to edit this value manually as well.
-
-- Uninstalling and reinstalling both the impacted packages and *all* the packages which transitively depend on them gives you the same behavior as an initial install… because that's exactly what you're doing. The downside, of course, is that you have to identify and uninstall and reinstall all top-level packages which transitively depend on the files, and this introduces risk by way of *other* transitive dependencies being updated.
diff --git a/tests/dummy/app/templates/docs/ts-guide/current-limitations.md b/tests/dummy/app/templates/docs/ts-guide/current-limitations.md
deleted file mode 100644
index 4bc60e18e..000000000
--- a/tests/dummy/app/templates/docs/ts-guide/current-limitations.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Current limitations
-
-While TS already works nicely for many things in Ember, there are a number of corners where it _won't_ help you out. Some of them are just a matter of further work on updating the [existing typings]; others are a matter of further support landing in TypeScript itself, or changes to Ember's object model.
-
-[existing typings]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ember
-
-## Some `import`s don't resolve
-
-You'll frequently see errors for imports which TypeScript doesn't know how to resolve. For example, if you use Ember Concurrency today and try to import its `task` helper:
-
-```typescript
-import { task } from 'ember-concurrency';
-```
-
-You'll see an error, because there aren't yet type definitions for it. You may see the same with some addons as well. **These won't stop the build from working;** they just mean TypeScript doesn't know where to find those.
-
-Writing these missing type definitions is a great way to pitch in! Jump in `#e-typescript` on the [Ember Community Discord server](https://discord.gg/zT3asNS) and we'll be happy to help you.
-
-## Templates
-
-Templates are currently totally non-type-checked. This means that you lose any safety when moving into a template context, even if using a Glimmer `Component` in Ember Octane.
-
-Addons need to import templates from the associated `.hbs` file to bind to the layout of any components they export. The TypeScript compiler will report that it cannot resolve the module, since it does not know how to resolve files ending in `.hbs`. To resolve this, you can provide this set of definitions to `my-addon/types/global.d.ts`, which will allow the import to succeed:
-
-{{#docs-snippet name='my-addon.d.ts' title='my-addon/types/global.d.ts' showCopy=true language='ts'}}
-declare module '*/template' {
- import { TemplateFactory } from 'htmlbars-inline-precompile';
-
- const template: TemplateFactory;
- export default template;
-}
-
-declare module 'app/templates/*' {
- import { TemplateFactory } from 'htmlbars-inline-precompile';
-
- const template: TemplateFactory;
- export default template;
-}
-
-declare module 'addon/templates/*' {
- import { TemplateFactory } from 'htmlbars-inline-precompile';
-
- const template: TemplateFactory;
- export default template;
-}
-{{/docs-snippet}}
-
-## Invoking actions
-
-TypeScript won't detect a mismatch between this action and the corresponding call in the template:
-
-{{#docs-snippet name='my-game.ts' title='my-app/components/my-game.ts' showCopy=false language='ts'}}
-import Component from '@ember/component';
-import { action } from '@ember-decorators/object';
-
-export default class MyGame extends Component {
- @action
- turnWheel(degrees: number) {
- // ...
- }
-}
-{{/docs-snippet}}
-
-{{#docs-snippet name='my-game.hbs' title='my-app/templates/components/my-game.hbs' showCopy=false language='htmlbars'}}
-
-{{/docs-snippet}}
-
-Likewise, it won't notice a problem when you use the `send` method:
-
-{{#docs-snippet name='nested-component.ts' title='my-app/components/nested-component.ts' showCopy=false language='ts'}}
-// TypeScript compiler won't detect this type mismatch
-this.send('turnWheel', 'ALSO-NOT-A-NUMBER');
-{{/docs-snippet}}
diff --git a/tests/dummy/app/templates/docs/type-defs/package-names.md b/tests/dummy/app/templates/docs/type-defs/package-names.md
deleted file mode 100644
index 5bf93c359..000000000
--- a/tests/dummy/app/templates/docs/type-defs/package-names.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Understanding the Package Names
-
-You may be wondering why the packages added to your `package.json` and described in [**Installation: Other packages this addon installs**][packages] are named things like `@types/ember__object` instead of something like `@types/@ember/object`. This is a conventional name used to allow both the compiler and the [DefinitelyTyped] publishing infrastructure ([types-publisher]) to handle scoped packages, documented under [What about scoped packages?][readme-h] in [the DefinitelyTyped README][readme].
-
-See also:
-
-- [Microsoft/types-publisher#155]
-- [Microsoft/Typescript#14819]
-
-[packages]: ../../docs#other-packages-this-addon-installs
-[DefinitelyTyped]: https://github.com/DefinitelyTyped/DefinitelyTyped
-[types-publisher]: https://github.com/Microsoft/types-publisher
-[readme-h]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master#what-about-scoped-packages
-[readme]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master
-[Microsoft/types-publisher#155]: https://github.com/Microsoft/types-publisher/issues/155
-[Microsoft/Typescript#14819]: https://github.com/Microsoft/TypeScript/issues/14819
diff --git a/tests/dummy/app/templates/docs/upgrade-notes.md b/tests/dummy/app/templates/docs/upgrade-notes.md
deleted file mode 100644
index 127d4dbf0..000000000
--- a/tests/dummy/app/templates/docs/upgrade-notes.md
+++ /dev/null
@@ -1,168 +0,0 @@
-# Upgrading from 1.x
-
-There are a number of important changes between ember-cli-typescript v1 and v2, which mean the upgrade process is *straightforward* but *specific*:
-
-1. Update ember-cli-babel. Fix any problems introduced during the upgrade.
-2. Update ember-decorators. Fix any problems introduced during the upgrade.
-3. Update ember-cli-typescript. Follow the detailed upgrade guide below to fix discrepancies between Babel and TypeScript's compiled output.
-
-If you deviate from this order, you are likely to have a *much* more difficult time upgrading!
-
-## Update ember-cli-babel
-
-ember-cli-typescript **requires** ember-cli-babel at version 7.1.0 or above, which requires ember-cli 2.13 or above. It also **requires** @babel/core 7.2.0 or higher.
-
-The recommended approach here is to deduplicate existing installations of the dependency, remove and reinstall ember-cli-babel to make sure that all its transitive dependencies are updated to the latest possible, and then to deduplicate *again*.
-
-If using yarn:
-
-```sh
-npx yarn-deduplicate
-yarn remove ember-cli-babel
-yarn add --dev ember-cli-babel
-npx yarn-deduplicate
-```
-
-If using npm:
-
-```sh
-npm dedupe
-npm uninstall ember-cli-babel
-npm install --save-dev ember-cli-babel
-npm dedupe
-```
-
-Note: If you are also using ember-decorators—and specifically the babel-transform that gets added with it—you will need update @ember-decorators/babel-transforms as well (anything over 3.1.0 should work):
-
-```sh
-ember install ember-decorators@^3.1.0 @ember-decorators/babel-transforms@^3.1.0
-```
-
-## Update ember-decorators
-
-Follow the same process of deduplication, reinstallation, and re-deduplication as described for ember-cli-babel above. This will get you the latest version of ember-decorators and, importantly, its @ember-decorators/babel-transforms dependency.
-
-## Update ember-cli-typescript
-
-Now you can simply `ember install` the dependency like normal:
-
-```sh
-ember install ember-cli-typescript@latest
-```
-
-***Note:* To work properly, starting from v2, ember-cli-typescript must be declared as a `dependency`, not a `devDependency` for addons. With `ember install` this migration would be automatically handled for you.**
-
-If you choose to make the upgrade manually with yarn or npm, here are the steps you need to follow:
-
-1. Remove ember-cli-typescript from your `devDependencies`.
-
- With yarn:
-
- ```sh
- yarn remove ember-cli-typescript
- ```
-
- With npm:
-
- ```sh
- npm uninstall ember-cli-typescript
- ```
-
-2. Install the latest of ember-cli-typescript as a `dependency`:
-
- With yarn:
-
- ```sh
- yarn add ember-cli-typescript@latest
- ```
-
- With npm:
-
- ```sh
- npm install --save ember-cli-typescript@latest
- ```
-
-3. Run `ember generate`:
-
- ```sh
- ember generate ember-cli-typescript
- ```
-
-### Account for addon build pipeline changes
-
-Since we now integrate in a more traditional way into Ember CLI's build pipeline, there are two changes required for addons using TypeScript.
-
-- Addons can no longer use `.ts` in `app`, because an addon's `app` directory gets merged with and uses the *host's* (i.e. the other addon or app's) preprocessors, and we cannot guarantee the host has TS support. Note that `.ts` will continue to work for in-repo addons because the app build works with the host's (i.e. the app's, not the addon's) preprocessors.
-
-- Similarly, apps must use `.js` to override addon defaults in `app`, since the different file extension means apps no long consistently "win" over addon versions (a limitation of how Babel + app merging interact).
-
-### Account for TS → Babel issues
-
-ember-cli-typescript v2 uses Babel to compile your code, and the TypeScript compiler only to *check* your code. This makes for much faster builds, and eliminates the differences between Babel and TypeScript in the build output that could cause problems in v1. However, because of those differences, you’ll need to make a few changes in the process of upgrading.
-
-Any place where a type annotation overrides a *getter*
-
-- Fields like `element`, `disabled`, etc. as annotated defined on a subclass of `Component` and (correctly) not initialized to anything, e.g.:
-
- ```ts
- import Component from '@ember/component';
-
- export default class Person extends Component {
- element!: HTMLImageElement;
- }
- ```
-
- This breaks because `element` is a getter on `Component`. This declaration then shadows the getter declaration on the base class and stomps it to `undefined` (effectively `Object.defineProperty(this, 'element', void 0)`.
-
- Two solutions:
-
- 1. Annotate locally (slightly more annoying, but less likely to troll you):
-
- ```ts
- class Image extends Component {
- useElement() {
- let element = this.element as HTMLImageElement;
- console.log(element.src);
- }
- }
- ```
-
- 2. Use a local getter:
-
- ```ts
- class Image extends Component {
- // We do this because...
- get _element(): HTMLImageElement {
- return this.element as HTMLImageElement;
- }
-
- useElement() {
- console.log(this._element.src);
- }
- }
- ```
-
-
-- `const enum` is not supported at all. You will need to replace all uses of `const enum` with simply `enum` or constants.
-
-- Using ES5 getters or settings with `this` type annotations is not supported through at least Babel 7.3. However, they should also be unnecessary with ES6 classes, so you can simply *remove* the `this` type annotation.
-
-- Trailing commas after rest function parameters (`function foo(...bar[],) {}`) are disallowed by the ECMAScript spec, so Babel also disallows them.
-
-- Re-exports of types have to be disambiguated to be *types*, rather than values. Neither of these will work:
-
- ```ts
- export { FooType } from 'foo';
- ```
-
- ```ts
- import { FooType } from 'foo';
- export { FooType };
- ```
-
- In both cases, Babel attempts to emit a *value* export, not just a *type* export, and fails because there is no actual value to emit. You can do this instead as a workaround:
-
- ```ts
- import * as Foo from 'foo';
- export type FooType = Foo.FooType;
- ```
diff --git a/tests/dummy/app/templates/index.hbs b/tests/dummy/app/templates/index.hbs
deleted file mode 100644
index 5a3e90842..000000000
--- a/tests/dummy/app/templates/index.hbs
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-