# Glimmer Component args & Typescript

**URL:** <https://discuss.emberjs.com/t/glimmer-component-args-typescript/17155>\
**Category:** Uncategorized\
**Created:** [October 24, 2019, 12:58pm UTC](https://discuss.emberjs.com/t/glimmer-component-args-typescript/17155 "2019-10-24T12:58:13Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![francesconovy](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/francesconovy/32/9607_2.png) [@francesconovy](https://discuss.emberjs.com/u/francesconovy)\
**Post date:** [October 24, 2019, 12:58pm UTC](https://discuss.emberjs.com/t/glimmer-component-args-typescript/17155/1 "2019-10-24T12:58:13Z")

</div>

I’ve been porting an addon to use Typescript, and ran into an issue I haven’t found a solution for - maybe somebody here can help me out.

How do I specify typings for `this.args` in a `@glimmer/component`?

I started from this baseline (slightly simplified, but it shows the issue):

```nohighlight
import Component from '@glimmer/component';
import { assert } from '@ember/debug';

export default class TextInput extends Component {
  constructor() {
    super(...arguments);

    assert(`onChange must be set`, typeof this.args.onChange === 'function');
  }
}

```

Which gives the error `Property "onChange" does not exist on type "Object"`.

Next I tried this:

```nohighlight
export default class TextInput extends Component {
  args: {
    onChange: Function
  };

  constructor() {
    super(...arguments);

    assert(`onChange must be set`, typeof this.args.onChange === 'function');
  }
}

```

Which fixed the Typescript Error, but lead to `args` always being undefined when running the app.

Finally I tried this:

```nohighlight
interface ArgsInterface {
  args: {
    onChange: Function;
  };
}

export default class TextInput extends Component implements ArgsInterface {
  constructor() {
    super(...arguments);

    assert(`onChange must be set`, typeof this.args.onChange === 'function');
  }
}

```

Which results in a TS error `Component TextInput incorrectly impelements ArgsInterface. Types of property args are incompatible.`.

Has anybody managed to get this to work properly?

---

<div class="post-metadata">

**Author:** ![chriskrycho](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/chriskrycho/32/17763_2.png) [@chriskrycho](https://discuss.emberjs.com/u/chriskrycho)\
**Post date:** [October 24, 2019, 1:20pm UTC](https://discuss.emberjs.com/t/glimmer-component-args-typescript/17155/2 "2019-10-24T13:20:31Z")

</div>

Hopefully we will have docs for this soon, but the trick here is that Glimmer components are generic over their arguments. So you write it like this:

```nohighlight
import Component from '@glimmer/component';
import { assert } from '@ember/debug';

interface Args {
  onChange: Function;
}

export default class TextInput extends Component<Args> {
  constructor(owner: unknown, args: Args) {
    super(...arguments);

    assert(`onChange must be set`, typeof args.onChange === 'function');
  }
}

```

This will also make `this.args` work as expected throughout.

* * *

Note that validating types manually this way in `constructor`, while better than nothing, won’t help if the arguments to the component _change_ over time. We’re still evaluating the best ways to help with that. Long term, type-checked template invocations will solve it, but @pzuraq and @dfreeman and I have played a bit with ideas around helpers to do this kind of thing nicely with zero runtime costs. Probably won’t have anything to show till late this year, but hopefully we _will_ have something to show then.

---

<div class="post-metadata">

**Author:** ![francesconovy](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/francesconovy/32/9607_2.png) [@francesconovy](https://discuss.emberjs.com/u/francesconovy)\
**Post date:** [October 24, 2019, 1:37pm UTC](https://discuss.emberjs.com/t/glimmer-component-args-typescript/17155/3 "2019-10-24T13:37:17Z")

</div>

That works just fine - thanks! No idea why, but I’m also just starting with Typescript, so maybe that will become clearer at some point in the future 😉

The `assert()` stuff used to be in `didReceiveAttrs`, but having it in `constructor` is “good enough” for most of our use cases. 🙂

---

<div class="post-metadata">

**Author:** ![chriskrycho](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/chriskrycho/32/17763_2.png) [@chriskrycho](https://discuss.emberjs.com/u/chriskrycho)\
**Post date:** [October 24, 2019, 1:53pm UTC](https://discuss.emberjs.com/t/glimmer-component-args-typescript/17155/4 "2019-10-24T13:53:38Z")

</div>

I highly recommend the [TypeScript Deep Dive](https://basarat.gitbooks.io/typescript/) book as a reference, if you’re just getting started! You’ll find [its chapter on generics](https://basarat.gitbooks.io/typescript/docs/types/generics.html) to be quite helpful on this specific bit.

In short, though, the type of Glimmer Component looks _something_ like this (there’s a bit more, but this is close enough for our purposes):

```nohighlight
class Component<Args extends {} = {}> {
  args: Args;

  constructor(owner: unknown, args: Args) {
    // sets up the component
  }
}

```

That 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<T>`, where `T` is the type of thing in the array, which TypeScript normally figures out for you automatically at compile time:

```nohighlight
let a = [1, 2, 3]; // Array<number>
let b = ["hello", "goodbye"]; // Array<string>

```

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<Args extends {}>`. 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<Args extends {} = {}>`.

I’ll try to expand this pair of answers into a blog post later this week, and also to work them into our documentation before Octane officially ships. 😅

---

<div class="post-metadata">

**Author:** ![francesconovy](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/francesconovy/32/9607_2.png) [@francesconovy](https://discuss.emberjs.com/u/francesconovy)\
**Post date:** [October 25, 2019, 8:37am UTC](https://discuss.emberjs.com/t/glimmer-component-args-typescript/17155/5 "2019-10-25T08:37:25Z")

</div>

Thanks very much for that - that definitely helps to understand what’s going on! Looking forward to your blog post 😉
