From 72a00dcc6b25d2cb0b90e09922314e03a1f54e29 Mon Sep 17 00:00:00 2001 From: mgechev Date: Wed, 3 Feb 2021 18:49:13 -0800 Subject: [PATCH] docs: add a style recommendation for initializing inputs (#40698) This practice is to better align with `strictPropertyInitialization` which is coming by default with strict mode in v12. PR Close #40698 --- .../styleguide/src/05-18/app/app.component.ts | 7 ++++++ .../styleguide/src/05-18/app/app.module.ts | 20 ++++++++++++++++ .../heroes/hero-list/hero-list.component.ts | 24 +++++++++++++++++++ .../src/05-18/app/heroes/hero-list/index.ts | 1 + .../app/heroes/hero/hero.component.avoid.ts | 15 ++++++++++++ .../heroes/hero/hero.component.optional.ts | 17 +++++++++++++ .../05-18/app/heroes/hero/hero.component.ts | 11 +++++++++ .../src/05-18/app/heroes/hero/index.ts | 1 + .../styleguide/src/05-18/app/heroes/index.ts | 3 +++ .../src/05-18/app/heroes/shared/hero.model.ts | 4 ++++ .../src/05-18/app/heroes/shared/index.ts | 1 + .../styleguide/src/05-18/app/index.ts | 2 ++ aio/content/guide/styleguide.md | 17 +++++++++++++ 13 files changed, 123 insertions(+) create mode 100644 aio/content/examples/styleguide/src/05-18/app/app.component.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/app.module.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/hero-list/hero-list.component.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/hero-list/index.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.avoid.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.optional.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/hero/index.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/index.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/shared/hero.model.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/heroes/shared/index.ts create mode 100644 aio/content/examples/styleguide/src/05-18/app/index.ts diff --git a/aio/content/examples/styleguide/src/05-18/app/app.component.ts b/aio/content/examples/styleguide/src/05-18/app/app.component.ts new file mode 100644 index 0000000000..86728b8b80 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: '' +}) +export class AppComponent { } diff --git a/aio/content/examples/styleguide/src/05-18/app/app.module.ts b/aio/content/examples/styleguide/src/05-18/app/app.module.ts new file mode 100644 index 0000000000..fe0b893ff2 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/app.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroComponent, HeroListComponent } from './heroes'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '05-18', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroComponent, + HeroListComponent + ], + exports: [AppComponent] +}) +export class AppModule {} diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/hero-list/hero-list.component.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/hero-list/hero-list.component.ts new file mode 100644 index 0000000000..5f82e7ec11 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/hero-list/hero-list.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; + +import { Hero } from '../shared/hero.model'; + +@Component({ + selector: 'toh-hero-list', + template: ` +
+ Our list of heroes: + + + Total powers: {{totalPowers}}
+ Average power: {{avgPower}} +
+ ` +}) +export class HeroListComponent { + heroes: Hero[] = []; + totalPowers = 1; + + get avgPower() { + return this.totalPowers / this.heroes.length; + } +} diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/hero-list/index.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/hero-list/index.ts new file mode 100644 index 0000000000..c4bcb3278e --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/hero-list/index.ts @@ -0,0 +1 @@ +export * from './hero-list.component'; diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.avoid.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.avoid.ts new file mode 100644 index 0000000000..6aa0a4edf4 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.avoid.ts @@ -0,0 +1,15 @@ +import { Component, Input } from '@angular/core'; + +// #docregion example +@Component({ + selector: 'toh-hero', + template: `...` +}) +export class HeroComponent { + // The exclamation mark suppresses errors that a property is + // not initialized. + // Ignoring this enforcement can prevent the type checker + // from finding potential issues. + @Input() id!: string; +} +// #enddocregion example diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.optional.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.optional.ts new file mode 100644 index 0000000000..f116c7d301 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.optional.ts @@ -0,0 +1,17 @@ +import { Component, Input } from '@angular/core'; + +// #docregion example +@Component({ + selector: 'toh-hero', + template: `...` +}) +export class HeroComponent { + @Input() id?: string; + + process() { + if (this.id) { + // ... + } + } +} +// #enddocregion example diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.ts new file mode 100644 index 0000000000..a8d5677fb4 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/hero/hero.component.ts @@ -0,0 +1,11 @@ +import { Component, Input } from '@angular/core'; + +// #docregion example +@Component({ + selector: 'toh-hero', + template: `...` +}) +export class HeroComponent { + @Input() id = 'default_id'; +} +// #enddocregion example diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/hero/index.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/hero/index.ts new file mode 100644 index 0000000000..084f36d703 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/hero/index.ts @@ -0,0 +1 @@ +export * from './hero.component'; diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/index.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/index.ts new file mode 100644 index 0000000000..dcf3e79bd3 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/index.ts @@ -0,0 +1,3 @@ +export * from './hero'; +export * from './hero-list'; +export * from './shared'; diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/shared/hero.model.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..a61b497759 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/shared/hero.model.ts @@ -0,0 +1,4 @@ +export interface Hero { + id: number; + name: string; +} diff --git a/aio/content/examples/styleguide/src/05-18/app/heroes/shared/index.ts b/aio/content/examples/styleguide/src/05-18/app/heroes/shared/index.ts new file mode 100644 index 0000000000..0dceb684c4 --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/heroes/shared/index.ts @@ -0,0 +1 @@ +export * from './hero.model'; diff --git a/aio/content/examples/styleguide/src/05-18/app/index.ts b/aio/content/examples/styleguide/src/05-18/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/aio/content/examples/styleguide/src/05-18/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/aio/content/guide/styleguide.md b/aio/content/guide/styleguide.md index 9064cfa7a7..5d8da7825c 100644 --- a/aio/content/guide/styleguide.md +++ b/aio/content/guide/styleguide.md @@ -3381,6 +3381,23 @@ helps instantly identify which members of the component serve which purpose. Back to top +### Initialize inputs + +#### Style 05-18 + +TypeScript's `--strictPropertyInitialization` compiler option ensures that a class initializes its properties during construction. When enabled, this option causes the TypeScript compiler to report an error if the class does not set a value to any property that is not explicitly marked as optional. + +By design, Angular treats all `@Input` properties as optional. When possible, you should satisfy `--strictPropertyInitialization` by providing a default value. + + + +If the property is hard to construct a default value for, use `?` to explicitly mark the property as optional. + + + +You may want to have a required `@Input` field, meaning all your component users are required to pass that attribute. In such cases, use a default value. Just suppressing the TypeScript error with `!` is insufficient and should be avoided because it will prevent the type checker ensure the input value is provided. + + ## Directives