Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why can it work without specifying an operator (@) in services? #21382

Closed
splincode opened this issue Jan 8, 2018 · 9 comments
Closed

Why can it work without specifying an operator (@) in services? #21382

splincode opened this issue Jan 8, 2018 · 9 comments
Labels
area: core Issues related to the framework runtime

Comments

@splincode
Copy link
Contributor

Adequate behavior

If I write this code, the compiler will swear

Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
Unexpected value 'AppComponent' declared by the module 'AppModule'. Please add a @Pipe/@Directive/@Component annotation

Inadequate behavior

But if I write this code, the compiler will not swear

app.component.ts

import { Component, Injectable } from '@angular/core';

Injectable() // thats without @
export class AuthService {
  constructor() {

  }
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor(public auth: AuthService) {

  }

}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent, AuthService } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [AuthService],
  bootstrap: [AppComponent]
})
export class AppModule { }

image

That is, I am purely allowed from the beginning to write Injectable without an operator (@). So, it can lead me here:

Uncertain behavior

app.component.ts

import { Component, Injectable } from '@angular/core';
import { HttpClient } from 'selenium-webdriver/http';

Injectable()
export class AuthService {
  constructor(private http: HttpClient) {

  }
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor(private auth: AuthService) {

  }

}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent, AuthService } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [AuthService],
  bootstrap: [AppComponent]
})
export class AppModule { }

image

Uncaught Error: Can't resolve all parameters for AuthService: (?).

But I would expect from the very beginning

Unexpected value 'AuthService' declared by the module 'AppModule'. Please add a @Injectable annotation

The worst after

The worst thing is that if I add an immediately missed statement (@), it means that ng serve does not work properly after that.

image

image

Environment

Angular version: 5.1.3
Browser: Chrome 63
Node version: 8.7.0
Windows 10

@skreborn
Copy link
Contributor

skreborn commented Jan 8, 2018

This happens because @ denotes a decorator. If you simply add Injectable, it does nothing. You might as well just write anything else there.

Injectable()
export class AuthService { ... }

// same as

console.log('this does nothing')
export class AuthService { ... }

If you add @Injectable though, you make TypeScript keep the class' types around. This is a bit of a "hack" to make dependency injection work. Without this, your application would have no idea what AuthService meant in runtime.

Note that the @Injectable decorator - unlike @Component, for example - is special, because it has no content, and isn't technically required for a service to work, it just helps with dependency injection.

Alternatively, you can omit the @Injectable decorator on services, and use the @Inject decorator in your constructors, but there really isn't any upsides to this approach.

export class AuthService { ... }

@Component({ ... })
export class AppComponent {
  constructor(@Inject(AuthService) private auth: AuthService) {}
}

In any case, I would classify this as working as intended and not a bug or shortcoming of Angular. I'm pretty sure that the requirement of using the @ character for decorators is explained clearly somewhere in the documentation.

@splincode
Copy link
Contributor Author

splincode commented Jan 8, 2018

But, unfortunately, this increases the learning curve... if taken for granted

@kemsky
Copy link

kemsky commented Jan 8, 2018

It seems that compiler check for Injectable is still missing, Component decorator is checked just because compiler need to use it to generate component. Injectable() is just a function call if used without @.

Also, see #18604:

@Injectable is still required for testing, hence it can't be removed.

It just doubles confusion about future and current state of Injectable .

@kara kara added the area: core Issues related to the framework runtime label Jan 8, 2018
@splincode
Copy link
Contributor Author

import { HttpClient } from 'selenium-webdriver/http';

Even if I connect the wrong service, it will not work until I add the correct @ operator, which means that there is no special check

@splincode
Copy link
Contributor Author

splincode commented Jan 8, 2018

It just doubles confusion about future and current state of Injectable

It's frustrating...

@trotyl
Copy link
Contributor

trotyl commented Jan 9, 2018

~~ It seems that compiler check for Injectable is still missing~~

Strict type-checking for @Injectable() already came in 5.0 version, see #19412

My bad it's not for checking misused decorator factory function.

It just doubles confusion about future and current state of Injectable .

@Injectable() will accept parameters like @Injectable(SomeModule, {deps: []}), then it's not an useless (conventional) decorator any more, see #20850

@splincode
Copy link
Contributor Author

Why would he do this? (Because, we are used to the old Injector)

@mhevery
Copy link
Contributor

mhevery commented Jan 9, 2018

Sorry this works as intended, even if it is confusing per explanation above.

@mhevery mhevery closed this as completed Jan 9, 2018
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: core Issues related to the framework runtime
Projects
None yet
Development

No branches or pull requests

6 participants