Brennan Karrer
Brennan Karrer

Reputation: 35

Handling Mixins with Ember CLI Typescript

Just wondering how / what is the best way to properly handle mixins with a typed ember application. Obviously eliminating mixins from the application would be best; however, most addons do not support typescript yet. With that said, what would be the best way to utilize ember-simple-auth application route mixin (or any of their mixins for that matter). I have not tested the following code but my guess is that something along these lines should work; however, it just feels a bit odd:

import Route from '@ember/routing/route';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';

export default class ApplicationRoute extends Route.extend(ApplicationRouteMixin, {
  // Prototype Code Here?
}) {
  // Class TS Code Here?
}

Once again, I have not tested this and am just beginning to embark on the TS journey so bear with me. Any help and clarification would be appreciated.

Upvotes: 3

Views: 752

Answers (1)

Chris Krycho
Chris Krycho

Reputation: 3155

You have the right basic tack going. Classic Ember Mixin instances have to be bound to the prototype. Note that everything that follows is equally applicable to ES6 classes; TypeScript classes are affected simply because they're mostly just types on ES6 classes.

import Route from '@ember/routing/route';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';

export default class ApplicationRoute extends Route.extend(ApplicationRouteMixin, {
  // anything required by the mixin has to go here
}) {
  // normal class code, which can *depend* on the mixin but is effectively
  // invisible to the mixin
}

One helpful way to think about this is that the object literal you're passing in to the class .extend() is itself just a mixin.

This pattern is best applied for backwards-compatible solutions or places where it's required by an addon. Mixins are difficult (at best) to type-check properly with TypeScript, and they have surprising and weird interactions with classes, as this example shows. (The strangenesses here would be equally applicable to plain JavaScript code using ES6 classes as well.)

Whenever you're writing new code, you're usually better off extracting the functionality to do one of a few options:

  • Use normal inheritance, with a single base class. Anywhere you have a single mixin, this is usually the most straightforward solution.

  • Switch to just defining pure functions, e.g. in app/lib/validation, and calling those with the appropriate arguments from the class instances.

Upvotes: 7

Related Questions