Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 37abe1f

Browse files
committed
feat: add a new page for advanced topics
Currently only discusses how `@Injectable()` works. We can add more in as time goes.
1 parent 2bcdb0a commit 37abe1f

File tree

6 files changed

+123063
-0
lines changed

6 files changed

+123063
-0
lines changed

‎content/fundamentals/advanced.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
### Advanced Concepts
2+
3+
So far we've breezed over a couple of advanced topics in Typescript like decorators and how the DI system is actually working under the hood. If all you want is a system that works, ou can probably move on to another section, but if you want to get a deeper understanding of how Nest works, this is the section for you.
4+
5+
#### The @Injectable() Decorator
6+
7+
Earlier in the docs we mentioned that "The `@Injectable()` decorator attaches metadata, which declares that `CatsService` is a class that can be managed by the Nest IoC container.". This is only a half truth, in reality, adding the provider to a module's `providers` array is what makes the provider able to be injected via the IoC container. What `@njectable()` is doing is forcing Typescript to emit metadata about the class's `constructor`, specifically the `design:paramtypes` metadata that will be read at start up. If there is an `@Inject()` decorator in the constructor, by technicality this does enough to make Typescript emit all the same metadata. Take a look at the compiled JavaScript from the following Typescript class:
8+
9+
```typescript
10+
export class Foo {
11+
constructor(private readonly foo: string) {}
12+
}
13+
14+
export class Bar {
15+
constructor(private readonly bar: string) {}
16+
}
17+
18+
export class FooBar {
19+
constructor(private readonly foo: Foo, private readonly bar: Bar) {}
20+
}
21+
```
22+
23+
The transpiled code would look like this
24+
25+
```javascript
26+
export class Foo {
27+
constructor(foo) {
28+
this.foo = foo;
29+
}
30+
}
31+
export class Bar {
32+
constructor(bar) {
33+
this.bar = bar;
34+
}
35+
}
36+
export class FooBar {
37+
constructor(foo, bar) {
38+
this.foo = foo;
39+
this.bar = bar;
40+
}
41+
}
42+
```
43+
44+
Now, let's add the `@Injectable()` decorator to the classes. We get the following output in our `dist`
45+
46+
```javascript
47+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
48+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
49+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
50+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
51+
return c > 3 && r && Object.defineProperty(target, key, r), r;
52+
};
53+
var __metadata = (this && this.__metadata) || function (k, v) {
54+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
55+
};
56+
let Foo = class Foo {
57+
constructor(foo) {
58+
this.foo = foo;
59+
}
60+
};
61+
Foo = __decorate([
62+
Injectable(),
63+
__metadata("design:paramtypes", [String])
64+
], Foo);
65+
export { Foo };
66+
let Bar = class Bar {
67+
constructor(bar) {
68+
this.bar = bar;
69+
}
70+
};
71+
Bar = __decorate([
72+
Injectable(),
73+
__metadata("design:paramtypes", [String])
74+
], Bar);
75+
export { Bar };
76+
let FooBar = class FooBar {
77+
constructor(foo, bar) {
78+
this.foo = foo;
79+
this.bar = bar;
80+
}
81+
};
82+
FooBar = __decorate([
83+
Injectable(),
84+
__metadata("design:paramtypes", [Foo, Bar])
85+
], FooBar);
86+
export { FooBar };
87+
```
88+
89+
There's a lot going on in the above snippet, so let's ignore the `__decorate` and `__metadata` method definitions and look just at the class portions. Notice that now there are metadata definitions for the `design:paramtypes` metadata key of `[String]` for `Foo` and `Bar` and `[Foo, Bar]` for `FooBar`. This tells Nest what parameters are expected in each position of the constructor for each class.
90+
91+
> info **Hint** When you use `@Inject('SomeString')` Nest will set `design:paramtypes` to `SomeString` for the position that you are decorating.
92+
93+
What Nest will do when reading this metadata is match it up with the class or injection token that exists in the current module's provider list and use that provider in the proper location for the constructor. This is why it is very important to either use a class, or `@Inject()` on the right parameter, and why all decorators cannot be used wherever you want.

‎src/app/homepage/menu/menu.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export class MenuComponent implements OnInit {
8080
path: '/fundamentals/platform-agnosticism',
8181
},
8282
{ title: 'Testing', path: '/fundamentals/testing' },
83+
{ title: 'Advanced', path: '/fundamentals/advanced' },
8384
],
8485
},
8586
{
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ChangeDetectionStrategy, Component } from '@angular/core';
2+
import { BasePageComponent } from '../../page/page.component';
3+
4+
@Component({
5+
selector: 'app-advanced',
6+
templateUrl: './advanced.component.html',
7+
changeDetection: ChangeDetectionStrategy.OnPush,
8+
})
9+
export class AdvancedComponent extends BasePageComponent {}

‎src/app/homepage/pages/fundamentals/fundamentals.module.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { PlatformAgnosticismComponent } from './platform-agnosticism/platform-ag
1313
import { ProviderScopesComponent } from './provider-scopes/provider-scopes.component';
1414
import { UnitTestingComponent } from './unit-testing/unit-testing.component';
1515
import { LazyLoadingModulesComponent } from './lazy-loading-modules/lazy-loading-modules.component';
16+
import { AdvancedComponent } from './advanced/advanced.component';
1617

1718
const routes: Routes = [
1819
{
@@ -86,6 +87,11 @@ const routes: Routes = [
8687
component: CircularDependencyComponent,
8788
data: { title: 'Circular Dependency' },
8889
},
90+
{
91+
path: 'advanced',
92+
component: AdvancedComponent,
93+
data: { title: 'Advanced Concepts' },
94+
},
8995
];
9096

9197
@NgModule({
@@ -102,6 +108,7 @@ const routes: Routes = [
102108
LifecycleEventsComponent,
103109
ModuleRefComponent,
104110
LazyLoadingModulesComponent,
111+
AdvancedComponent,
105112
],
106113
})
107114
export class FundamentalsModule {}

‎tags.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
580418

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /