Skip to content

Commit 59e7ced

Browse files
committed
Merge remote-tracking branch 'origin/master' into include-ember-destroyable-types
2 parents e15a471 + ef5aa5f commit 59e7ced

File tree

4 files changed

+136
-265
lines changed

4 files changed

+136
-265
lines changed

docs/ember/components.md

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,46 @@ export default class Counter extends Component {
3636

3737
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.
3838

39-
## Adding arguments
39+
## Adding arguments and giving them a type
4040

4141
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.
4242

43-
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:
43+
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.
44+
45+
Since the implementation of [RFC 748], Glimmer and Ember components accept a `Signature` type parameter as part of their definition. This parameter is expected to be an object type with (up to) three members: `Args`, `Element` and `Blocks`.
46+
47+
[rfc 748]: https://github.com/emberjs/rfcs/pull/748
48+
49+
`Args` represents the arguments your component accepts. Typically this will be an object type mapping the names of your args to their expected type. For example:
50+
51+
```
52+
export interface MySignature {
53+
Args: {
54+
arg1: string;
55+
arg2: number;
56+
arg3: boolean;
57+
}
58+
}
59+
```
60+
If no `Args` key is specified, it will be a type error to pass any arguments to your component. You can read more about `Element` and `Block` in the Glint [Component Signatures documentation](https://typed-ember.gitbook.io/glint/using-glint/ember/component-signatures).
61+
62+
Let’s imagine a component which just logs the names of its arguments when it is first constructed. First, we must define the Signature and pass it into our component, then we can use the `Args` member in our Signature to set the type of `args` in the constructor:
4463

4564
```typescript
4665
import Component from '@glimmer/component';
4766

4867
const log = console.log.bind(console);
4968

50-
export default class ArgsDisplay extends Component {
51-
constructor(owner: unknown, args: {}) {
69+
export interface ArgsDisplaySignature {
70+
Args: {
71+
arg1: string;
72+
arg2: number;
73+
arg3: boolean;
74+
}
75+
}
76+
77+
export default class ArgsDisplay extends Component<ArgsDisplaySignature> {
78+
constructor(owner: unknown, args: ArgsDisplaySignature['Args]) {
5279
super(owner, args);
5380

5481
Object.keys(args).forEach(log);
@@ -69,24 +96,22 @@ Notice that we have to start by calling `super` with `owner` and `args`. This ma
6996
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.
7097
{% endhint %}
7198
72-
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.
73-
74-
`{}` 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:
75-
76-
> any thing that is not `number`, `string`, `boolean`, `symbol`, `null`, or `undefined`.
77-
78-
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.
79-
80-
{% hint style="info" %}
81-
For some further details, check out [this blog post](https://mariusschulz.com/blog/the-object-type-in-typescript).
82-
{% endhint %}
99+
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 the `Args` from the Signature we defined.
83100
84101
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:
85102
86103
```typescript
87104
import Component from '@glimmer/component';
88105

89-
export default class ArgsDisplay extends Component {
106+
export interface ArgsDisplaySignature {
107+
Args: {
108+
arg1: string;
109+
arg2: number;
110+
arg3: boolean;
111+
}
112+
}
113+
114+
export default class ArgsDisplay extends Component<ArgsDisplaySignature> {
90115
get argNames(): string[] {
91116
return Object.keys(this.args);
92117
}
@@ -192,4 +217,3 @@ export default class FancyInput<Args extends FancyInputArgs = FancyInputArgs> ex
192217
```
193218
194219
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.
195-

docs/ts/with-addons.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ When you publish an addon written in TypeScript, the `.ts` files will be consume
1515

1616
Even though you publish the source `.ts` files, though, by default you consumers who also use TypeScript won't be able to benefit from those types, because the TS compiler isn't aware of how `ember-cli` resolves import paths for addon files. For instance, if you write `import { foo } from 'my-addon/bar';`, the typechecker has no way to know that the actual file on disk for that import path is at `my-addon/addon/bar.ts`.
1717

18-
In order for your addon's users to benefit from type information from your addon, you need to put `.d.ts` _declaration files_ at the location on disk where the compiler expects to find them. This addon provides two commands to help with that: `ember ts:precompile` and `ember ts:clean`. The default `ember-cli-typescript` blueprint will configure your `package.json` to run these commands in the `prepublishOnly` and `postpublish` phases respectively, but you can also run them by hand to verify that the output looks as you expect.
18+
In order for your addon's users to benefit from type information from your addon, you need to put `.d.ts` _declaration files_ at the location on disk where the compiler expects to find them. This addon provides two commands to help with that: `ember ts:precompile` and `ember ts:clean`. The default `ember-cli-typescript` blueprint will configure your `package.json` to run these commands in the `prepack` and `postpack` phases respectively, but you can also run them by hand to verify that the output looks as you expect.
1919

2020
The `ts:precompile` command will populate the overall structure of your package with `.d.ts` files laid out to match their import paths. For example, `addon/index.ts` would produce an `index.d.ts` file in the root of your package.
2121

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,18 @@
6060
"@types/capture-console": "1.0.1",
6161
"@types/chai": "4.3.0",
6262
"@types/chai-as-promised": "7.1.4",
63-
"@types/console-ui": "2.2.5",
63+
"@types/console-ui": "2.2.6",
6464
"@types/core-object": "3.0.1",
6565
"@types/debug": "4.1.7",
66-
"@types/ember": "4.0.0",
66+
"@types/ember": "4.0.1",
6767
"@types/ember-qunit": "5.0.0",
6868
"@types/esprima": "4.0.3",
6969
"@types/express": "4.17.13",
7070
"@types/fs-extra": "9.0.13",
7171
"@types/got": "9.6.12",
7272
"@types/mocha": "9.1.0",
7373
"@types/node": "14.14.8",
74-
"@types/qunit": "2.11.3",
74+
"@types/qunit": "2.19.3",
7575
"@types/resolve": "1.20.1",
7676
"@types/semver": "7.3.9",
7777
"@typescript-eslint/eslint-plugin": "5.10.1",

0 commit comments

Comments
 (0)