Parameter decoration is leveraged in Aurelia factory resolver (instead of class decoration)

I have experience using the Aurelia factory resolver with the @inject class decorator:

@inject(Factory.of(Foo))
export class NeedsFoo {
  foo: Foo;
  constructor(fooFactory: () => Foo) {
    this.foo = fooFactory(config);
  }
}

The config parameter is necessary to initialize the Foo instance, but it cannot be injected.

In larger view models, I find that @autoinject is more convenient for managing dependencies. However, I am struggling to replicate the functionality using parameter decorators.

The documentation on resolvers is brief and lacks an example of the factory resolver property. There is a related bug reported, but understanding its usage has been challenging. Although there are discussions on Stack Overflow, they all revolve around @inject(Factory.of(...)).

When attempting the following approach, the fooFactory object appears as an empty object {}:

@autoinject()
export class NeedsFoo {
  foo: Foo;
  constructor(@factory(Foo) fooFactory) {
    this.foo = fooFactory(config);
  }
}

A comment in the bug discussion suggests this solution:

interface FooFactory {
  new (config: any): Foo;
}

class NeedsFoo {
  foo: Foo;
  constructor(@factory(Foo) fooFactory: FooFactory) {
    this.foo = new fooFactory(config); // error!
  }
}

However, utilizing the marked line results in a

TypeError: fooFactory is not a constructor
error (as it's an empty object).

Is it possible to use parameter decorators and autoinject to inject a factory of a class in Aurelia?


edit: changed deps to config to avoid confusion regarding passing injected dependencies.

edit 2: clarification - fooFactory appears as an empty object, not undefined

Answer №1

You are on the verge of success! In your second example, simply add @autoinject() to NeedsFoo, remove the deps argument, and remember to also include @autoinject() on Foo if it has its own dependencies.

To clarify how and why this method works while dispelling some misconceptions:

  • Any decorator added to a class will prompt tsc to generate type metadata for that class. The use of autoinject is only necessary when there are no other decorators present on the class. If a class is already tagged with @customElement(), then there is no need for @autoinject().

  • Passing dependencies into the factory function is not required. The container handles dependency retrieval internally within the factory function.

  • The factory function serves as a constructor function, not a class constructor. Both fooFactory() and new fooFactory() achieve the same result - invoking the function and returning its output.

  • Interfaces do not translate to javascript. Using an interface as an argument type does not facilitate DI functionality. In this context, : FooFactory is equivalent to : any. It primarily aids in providing intellisense support.

  • When employing @factory(), the type passed to the function supersedes the type specified for the argument itself. The argument's declared type becomes irrelevant.

This approach offers multiple variations for implementation.

Assuming the presence of class Foo:

@autoinject()
export class Foo {
    public bar: Bar;
    constructor(bar: Bar) {
        this.bar = bar;
    }
}

And considering various implementations of NeedsFoo:

@autoinject()
export class NeedsFoo {
    public foo: Foo;
    constructor(@factory(Foo) fooFactory: any) {
        this.foo = new fooFactory();
    }
}

@customElement("needs-foo")
export class NeedsFoo {
    public foo: Foo;
    constructor(@factory(Foo) fooFactory: FooFactory) {
        this.foo = new fooFactory();
    }
}

@autoinject()
export class NeedsFoo {
    public foo: Foo;
    constructor(@factory(Foo) fooFactory: any) {
        this.foo = fooFactory();
    }
}

@autoinject()
export class NeedsFoo {
    public foo: Foo;
    constructor(@factory(Foo) fooFactory: FooFactory ) {
        this.foo = new fooFactory();
    }
}
interface FooFactory {
    new(): Foo;
}

All these options, along with their potential combinations, yield similar outcomes by producing an instance of Foo as expected.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the proper way to invoke a child method after converting an object from a parent class to a child class?

When we have a subclass B that overrides a method from its superclass A in TypeScript, why does calling the method on an instance of A result in the parent class's implementation being called? In TypeScript, consider a class called Drug with properti ...

Having trouble accessing undefined properties? Facing issues with the latest Angular version?

Why am I encountering an error and what steps can be taken to resolve it? Currently using the latest version of Angular. ERROR TypeError: Cannot read properties of undefined (reading 'id') Here is the JSON data: { "settings": [ { ...

The ordering of parameters should not impact the functionality of Typescript generics, though currently it does

My mergeArrays generic function is designed to not rely on the order of parameters. However, when it is used within another generic function, the result seems to depend on the order. This unexpected behavior is puzzling. type Fn = (...args: any[]) => an ...

What is the best way to define a precise return type for a JSX Element?

Is it possible to define a function that returns a Button element and what would the correct return type of the function be? For example: Ex: const clickMeButton = (): Button => { return ( <Button> Click Me </Button& ...

Tips for retrieving the return value from a function with an error handling callback

I am having an issue with my function that is supposed to return data or throw an error from a JSON web token custom function. The problem I am facing is that the data returned from the signer part of the function is not being assigned to the token const a ...

Utilize Optional Chaining for verifying null or undefined values

I have utilized the following code: data?.response[0]?.Transaction[0]?.UID; In this scenario, the Transaction key is not present, resulting in the error message: ERROR TypeError: Cannot read properties of undefined (reading '0') Instead of chec ...

Steps for converting an observable http request into a promise request

Here is a link to my service file: https://i.sstatic.net/8dsMx.png This is the TypeScript file for my components: https://i.sstatic.net/of6sx.png And these are the response models: https://i.sstatic.net/U8RUQ.png https://i.sstatic.net/7baTj.png I am curre ...

Reduce the use of if statements

Is there a way to optimize this function by reducing the number of if statements? The currentFeatures are determined by a slider in another file. The cost is updated if the currentFeatures do not match the previousFeatures, and if the user changes it back ...

The transition to CDK version 2 resulted in a failure of our test cases

After upgrading my CDK infrastructure code from version 1 to version 2, I encountered some failed test cases. The conversion itself was successful without any issues. The only changes made were updating the references from version 1 to version 2, nothing ...

What are the steps to implement a Bottom Navigation bar in iOS and a Top Navigation bar in Android using NativeScript Angular?

For my project, I decided to utilize the tns-template-tab-navigation-ng template. I am currently working on creating a WhatsApp clone, and in iOS, it features a bottom navigation bar while in Android, it has a top navigation bar. I am looking for guidance ...

Develop a Typescript interface containing all the necessary properties for a specific JSX component

My goal is to create a ControlledInputComponent that consists of a label and an input inside a div. I aim to make it highly customizable as I plan on using it in various ways. At the moment, I have included all the necessary elements, but I would like to e ...

Can TypeScript automatically deduce keys from a changing object structure?

My goal here is to implement intellisense/autocomplete for an object created from an array, similar to an Action Creator for Redux. The array consists of strings (string[]) that can be transformed into an object with a specific shape { [string]: string }. ...

Retrieve data from TypeScript file (.ts) and use it in an HTML document

Recently I started learning Typescript and HTML as I work on building an Angular2 application. At the moment, I have a TypeScript file that resembles the following structure: import {Http, Headers} from 'angular2/http'; import {Component} from & ...

Tips for utilizing withNavigation from react-navigation in a TypeScript environment

Currently, I am working on building an app using react-native, react-navigation, and typescript. The app consists of only two screens - HomeScreen and ConfigScreen, along with one component named GoToConfigButton. Here is the code for both screens: HomeSc ...

Learn how to efficiently disable or enable a button in Angular depending on the selected radio button

In order to disable the button when the remarks are marked as failed. Here is an example scenario: Imagine there is an array containing two to four items. First example: ITEM 1 -> FAILED -> Remarks (required) ITEM 2 -> FAILED -> Remarks (r ...

Loading data into the Nuxt store upon application launch

Currently, I'm working on an app using Nuxt where I preload some data at nuxtServerInit and store it successfully. However, as I have multiple projects with similar initial-preload requirements, I thought of creating a reusable module for this logic. ...

Reinstalling node does not remove Typescript, as it remains intact even after the

When I was working on my Angular 5 project, I encountered the following error during compilation: @angular/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="31525e5c41585d54431c525d5871041f031f0000">[email protected]</ ...

Troubles with Angular2 template parser when parsing HTML fragment that is W3C validated

The online W3C validator successfully parses the following document: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>test</title> </head&g ...

What could be causing useFormik to automatically update the initial value?

I have a component structure that looks like this. Please note that the actual code may differ from this, but this is to help you visualize. <EditAssessment> <AssessmentForm> <AssessmentScheduleCronWeekField> </Asses ...

How can I swap a string for a symbol in JavaScript?

Is there a way to convert the text @abc some text here to <a href="some_url">@abc</a> some text here using JavaScript? Are there any libraries that can help with this task? ...