4

I can't understand why the next issue happens. Code with the same structure works fine in any other object-oriented languages like C# or Java. I am writing Node.Js app using Typescript.

So I have a class ServiceLocator with two static variables:

//ServiceLocator.ts
export class ServiceLocator {
    public static dataRepository: IDataRepository = new DataRepository();
    public static authService: IAuthService = new AuthService();
}

Class from the second one variable using the first one static variable. This how it looks:

//AuthService.ts
const dataRepository: IDataRepository = ServiceLocator.dataRepository;
export class AuthService implements IAuthService {
...
}

But once I am trying to get authService link like this:

//AuthController.ts
const authService: IAuthService = ServiceLocator.authService;
export class AuthController {

    public async signIn(request: Request, response: Response) {
        ..
    }
..
}

I got an error:

 TypeError: Cannot read property 'dataRepository' of undefined

What am I do wrong?

1
  • Did you import the ServiceLocator in AuthController.ts? Commented May 1, 2019 at 4:58

1 Answer 1

1

You have a circular reference here. In order to construct the AuthService module you need a fully constructed ServiceLocator class. However, JavaScript needs a fully constructed AuthService module in order to construct the ServiceLocator class. Switching the order of instantiation would simply result in an error from ServiceModule <cint> (to coin a Java-ism) along the lines of "Uncaught TypeError: undefined is not a constructor".

The solution is to simply make the dependency lazy:

//AuthService.ts
const dataRepositoryReference: IDataRepository = import('./ServiceLocator')
  .then(({ ServiceLocator }) => ServiceLocator.dataRepository);
export class AuthService implements IAuthService {
  public async findUserByUsername(username: UserName) {
    const dataRepository = await dataRepositoryReference;
    // ... snip ...
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, this solution works fine but then I need to create repository reference in each method. This will provide a lot of code duplication as far as I have a few such references. Do you have any ideas on how to avoid this?
This is how I trying to do that without method integration. But obviously, it looks not pretty good for me. What do you think? codeshare.io/5zk7r4
Using a side effect to set the binding asynchronously is a recipe for random null pointer exceptions (when findByUsername gets executed before .then({ xValue }) => xBinding = xValue)). You can make it a little better by keeping the promise around and using it as a latch (but that's almost as fragile without a lint rule).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.