Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Octane and much polish and clarification #935

Merged
merged 131 commits into from
Dec 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
0978813
docs: begin work on Octane docs push
chriskrycho Nov 6, 2019
d5bf2e2
docs: add constructor to simplified Component definition
chriskrycho Nov 6, 2019
6bd300a
docs: clarify `this.args` in Glimmer component docs
chriskrycho Nov 6, 2019
6c1f58f
docs: make some small improvements to Glimmer Component page
chriskrycho Nov 9, 2019
5b4d971
docs: start the Legacy Ember Components page
chriskrycho Nov 9, 2019
c1fc7a7
docs: fix a typo in Glimmer docs
chriskrycho Nov 9, 2019
d19c2cb
docs: begin work on testing page
chriskrycho Nov 22, 2019
b65a980
docs: add more material about tests
chriskrycho Nov 22, 2019
0204699
docs: auto deploy draft Octane docs
dfreeman Nov 22, 2019
937b014
docs: set explicit version path in docs deploy
dfreeman Nov 23, 2019
55289b5
docs: add new outline structure
chriskrycho Dec 5, 2019
d1b6e33
docs: remove duplicate docs
chriskrycho Dec 5, 2019
993acbb
docs: rename 'Setup' to 'Getting Started'
chriskrycho Dec 7, 2019
e79d768
docs: tweak invocation of DocsViewer in docs template
chriskrycho Dec 7, 2019
69bbb21
docs: drop unneeded root guide template
chriskrycho Dec 7, 2019
b9082c6
docs: put general disclaimer in index
chriskrycho Dec 7, 2019
f9d4c41
docs: header for Apps and Addons page
chriskrycho Dec 7, 2019
8b17cc6
docs: improve text of Legacy Overview
chriskrycho Dec 7, 2019
b54ff71
docs: improve text and fix headings of Testing guide
chriskrycho Dec 7, 2019
0fbadb8
docs: use DocViewer in components guide
chriskrycho Dec 7, 2019
698491b
docs: fix bad link-to invocation
chriskrycho Dec 7, 2019
ccd00ef
docs: add Getting Started root page template
chriskrycho Dec 7, 2019
52d0ad1
docs: add root Getting Started template
chriskrycho Dec 7, 2019
b9f3c7b
docs: drop Getting Started template, change links
chriskrycho Dec 7, 2019
701d763
Merge branch 'master' into octane-docs
jamescdavis Dec 7, 2019
a248694
Merge branch 'master' into octane-docs
chriskrycho Dec 9, 2019
42fe756
docs: clarify `...arguments` unsafety
chriskrycho Dec 9, 2019
b7e4e99
docs: elaborate on `super` and `this`
chriskrycho Dec 9, 2019
14d031e
docs: use demo and snippet for Component docs
chriskrycho Dec 9, 2019
ed3970b
docs: continue building out component guide
chriskrycho Dec 9, 2019
000184d
docs: begin filling out Helper guide
chriskrycho Dec 19, 2019
b6c8cd4
chore(deps): merge latest changes from master
chriskrycho Dec 19, 2019
5847eea
docs: fix demo example in helpers guide
chriskrycho Dec 19, 2019
568e17f
docs: iterate on component examples
chriskrycho Dec 22, 2019
e91e2c0
chore(deps): update dependency ember-cli-addon-docs to v0.6.16
jamescdavis Jan 18, 2020
65164e6
chore(deps): upgrade dependency ember-cli-addon-docs to b180220
jamescdavis Jan 18, 2020
0f4f9fb
docs: improve helper examples
chriskrycho Jan 20, 2020
5766e28
docs: clarify example in helper docs
chriskrycho Jan 20, 2020
2325dee
docs: simplify functional helper type
chriskrycho Jan 20, 2020
3b29e4f
docs: restructure to support Ember Data
chriskrycho Jan 20, 2020
9149904
docs: include prettier fixes from master
chriskrycho Jan 20, 2020
6f247a6
docs: basic overview text for Ember section
chriskrycho Jan 20, 2020
169935f
docs: rename and restructure TS route section
chriskrycho Jan 20, 2020
b029a86
docs: fix Ember guide references to match 3b29e4f
chriskrycho Jan 20, 2020
59b7861
docs: add content and another stub for Ember Data
chriskrycho Jan 20, 2020
bd8ee91
docs: make overview reflect new structure
chriskrycho Jan 20, 2020
d4041b5
docs: fill out `@attr` guide
chriskrycho Jan 20, 2020
9e03eee
docs: add an intro to Model guide
chriskrycho Jan 20, 2020
7e03549
docs: explain `@belongsTo` usage and caveats
chriskrycho Jan 20, 2020
43ed5e8
docs: explain Promise(Object|ManyArray) imports
chriskrycho Jan 20, 2020
2b909d5
docs: explain `@hasMany` usage and caveats
chriskrycho Jan 20, 2020
0bf5b58
docs: extract has-many and belongs-to to snippets
chriskrycho Jan 20, 2020
bfeda3c
docs: exclude snippets from type-checking
chriskrycho Jan 20, 2020
5acf6c1
docs: add Services guide
jamescdavis Jan 22, 2020
356fc31
docs: note our inclusion of blueprints
chriskrycho Jan 22, 2020
09edd28
docs: improve main overview outline
chriskrycho Jan 22, 2020
601f0cb
docs: extract CP `this` discussion to own page
chriskrycho Jan 23, 2020
0ca18d9
docs: add snippet files for services guide
jamescdavis Jan 23, 2020
67fa036
docs: actually include CP guide
chriskrycho Jan 24, 2020
5161e81
docs: add a cookbook section and one "recipe"
chriskrycho Jan 24, 2020
f010a3c
docs: add non-null assertion to service injections
jamescdavis Jan 28, 2020
7165edf
docs: add explanation of needing non-null assertion for service injec…
jamescdavis Jan 29, 2020
3fcf219
docs: better formatting for bad service usage comment
jamescdavis Jan 29, 2020
657f25c
docs: add caution about type-casting service lookups
jamescdavis Jan 29, 2020
09314f8
Merge remote-tracking branch 'origin/master' into octane-docs
chriskrycho Nov 23, 2020
bf86338
chore(deps): update deps after merge
chriskrycho Nov 23, 2020
fe4e72e
docs: recommend `declare` instead of definite-initialization
chriskrycho Nov 23, 2020
8b7f386
chore(ci): use Node 10 for Docs publishing
chriskrycho Nov 23, 2020
d9ad89e
docs: recommend TrackedArray over EmberArray
chriskrycho Nov 23, 2020
2df9346
docs: update note on service lookup cast
chriskrycho Nov 23, 2020
891f258
docs: explain `declare` instead of definite initialization
chriskrycho Nov 23, 2020
108c561
docs: describe use of `declare` instead of `!`
chriskrycho Nov 23, 2020
38188ad
docs: further `!` -> `declare` improvements
chriskrycho Nov 23, 2020
292765c
docs: clarify issues, solutions in conflicting-types
chriskrycho Nov 23, 2020
d641e26
docs: fix Ember Data imports and remove outdated blog links
chriskrycho Nov 23, 2020
7f57d0a
docs: fix more Ember Data references
chriskrycho Nov 23, 2020
a0116b6
docs: remove reference to ember-browserify
chriskrycho Nov 23, 2020
c89eb3c
docs: routing
chriskrycho Nov 23, 2020
25bc558
docs: controllers
chriskrycho Nov 23, 2020
e704980
docs: clarify that `noEmitOnError: true` fails your build
chriskrycho Nov 23, 2020
92a0bd5
docs: remove pages for adapters, serializers, and transforms
chriskrycho Nov 23, 2020
0d24bc8
docs: on legacy computed properties
chriskrycho Nov 23, 2020
7da5e0e
docs: mixins -- mostly for how to migrate away!
chriskrycho Nov 23, 2020
dfc410b
docs: remove page on EmberComponent
chriskrycho Nov 23, 2020
745ae42
docs: on generics in subclasses
chriskrycho Nov 23, 2020
b46c16c
docs: fix a TODO link
chriskrycho Nov 23, 2020
482b727
docs: fix remaining TODOs in helper docs
chriskrycho Nov 23, 2020
2811d5b
docs: fix TODO links in helpers docs
chriskrycho Nov 23, 2020
99bd07e
docs: fix TODOs in testing guide
chriskrycho Nov 23, 2020
79fc492
docs: fix a TODO in overview
chriskrycho Nov 23, 2020
dae619f
docs: improve legacy guide
chriskrycho Nov 23, 2020
7758f88
docs: begin reworking into a Gitbook repo
chriskrycho Nov 24, 2020
d68b24b
chore(docs): configuring GitBook
chriskrycho Nov 24, 2020
4176b19
docs: replace a docs snippet with inlined example
chriskrycho Nov 24, 2020
de57fb4
docs: gitbook-ready components page
chriskrycho Nov 24, 2020
29f6414
docs: simplify installation writeup
chriskrycho Nov 24, 2020
0203bac
docs: further de-addon-docs-ing of component guide
chriskrycho Nov 24, 2020
006c144
docs: drop inlined snippet
chriskrycho Nov 24, 2020
f618237
docs: de-addon-docs-ify helpers guide
chriskrycho Nov 24, 2020
c864adc
docs: de-addon-docs-ify services guide
chriskrycho Nov 24, 2020
3d6e42c
docs: elaborate tracked-built-ins rec
chriskrycho Nov 24, 2020
51ec9ac
docs: drop pages for adapters, serializers, transforms
chriskrycho Nov 24, 2020
78d169a
docs: de-addon-docs-ify Ember Data Model guide
chriskrycho Nov 24, 2020
3ca1974
docs: de-addon-docs-ify working-with-route-models
chriskrycho Nov 24, 2020
049b095
docs: drop now-unused snippets
chriskrycho Nov 24, 2020
5543bba
docs: remove addon-docs from dummy app router
chriskrycho Nov 24, 2020
8130565
docs: clean up other addon-docs implementation
chriskrycho Nov 24, 2020
1622992
docs: drop now-unneeded docs action
chriskrycho Nov 24, 2020
adb53ab
docs: replace asides with hints or warnings
chriskrycho Nov 24, 2020
3a434de
docs: fix gitbook config for summary
chriskrycho Nov 24, 2020
e55338e
docs: update from GitBook -- 37 pages modified
chriskrycho Nov 24, 2020
4f1aa36
docs: remove now-unnecessary ember-cli-deploy
chriskrycho Nov 24, 2020
9a6c2c1
docs: restructure and use Gitbook style
chriskrycho Nov 24, 2020
3734a03
docs: fix links for installation and configuration
chriskrycho Nov 24, 2020
7a43168
docs: fix capitalization of Cookbook
chriskrycho Nov 24, 2020
91f1556
docs: fix another link
chriskrycho Nov 24, 2020
ee8fae9
docs: internal linking and organization
chriskrycho Nov 24, 2020
3d80a5f
docs: further improve outline
chriskrycho Nov 24, 2020
3cd77bb
docs: include index in outline
chriskrycho Nov 24, 2020
496fa76
docs: remove needless references to ember-decorators
chriskrycho Nov 24, 2020
4dcb2de
docs: tweak grammar on landing page
chriskrycho Nov 24, 2020
edafc5f
docs: remove content from using-ts-effectively
chriskrycho Nov 24, 2020
30eb350
docs: improve Decorators page content
chriskrycho Nov 24, 2020
0f9f088
docs: clarify/correct language around Babel config
chriskrycho Nov 24, 2020
1a593e8
docs: add outline to Working With Ember page
chriskrycho Nov 24, 2020
f35db2b
docs: improve installation writuep
chriskrycho Nov 24, 2020
83724cf
docs: fix links in primary overview
chriskrycho Nov 24, 2020
66256f1
docs: improve Using TS With Ember Effectively
chriskrycho Nov 24, 2020
979f16d
docs: eliminate needless escaping of parentheses
chriskrycho Nov 24, 2020
6d0f586
Merge branch 'master' into octane-docs
chriskrycho Dec 21, 2020
7d6628a
chore: fix accidentally misconfigured lint setting
chriskrycho Dec 22, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down
4 changes: 4 additions & 0 deletions .gitbook.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
root: ./docs

structure:
readme: ./index.md
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
12 changes: 0 additions & 12 deletions config/addon-docs.js

This file was deleted.

29 changes: 0 additions & 29 deletions config/deploy.js

This file was deleted.

31 changes: 31 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -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)

Original file line number Diff line number Diff line change
@@ -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',
Expand Down
12 changes: 12 additions & 0 deletions docs/cookbook/README.md
Original file line number Diff line number Diff line change
@@ -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)

51 changes: 51 additions & 0 deletions docs/cookbook/working-with-route-models.md
Original file line number Diff line number Diff line change
@@ -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> = P extends Promise<infer T> ? T : P;

/** Get the resolved model value from a route. */
export type ModelFrom<R extends Route> = Resolved<ReturnType<R['model']>>;
```

How that works:

* `Resolved<P>` says "if this is a promise, the type here is whatever the promise resolves to; otherwise, it's just the value"
* `ReturnType<T>` 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<Route>` ends up giving you the resolved value returned from the `model` hook for a given route:

```typescript
type MyRouteModel = ModelFrom<MyRoute>;
```

## `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<MyRoute>;
}
```

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.

6 changes: 6 additions & 0 deletions docs/ember-data/README.md
Original file line number Diff line number Diff line change
@@ -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)!

124 changes: 124 additions & 0 deletions docs/ember-data/models.md
Original file line number Diff line number Diff line change
@@ -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<Model>`, 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<User>;

@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<Model>`, where `Model` is the type of the model you are creating a relationship to.
* If the value is `false`, the type is `EmberArray<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, { 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<Comment>;

@hasMany('user', { async: false })
declare participants: EmberArray<User>;
}
```

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<Model>` and `Promise<Array<Model>>`.

15 changes: 15 additions & 0 deletions docs/ember/README.md
Original file line number Diff line number Diff line change
@@ -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)
Loading