Angular v20 の**推奨スタイル(Signals/inject/toSignal/ライフサイクル不要)**で書き直すと、
以下のように class コンストラクタをやめて inject() を使い、OnInit を外し、valueChanges を toSignal に変換して effect で emit する構成がベスト。
⸻
✅ v20 推奨構成で書き換えたコード(最小・最もきれい)
ポイント:
• inject(FormBuilder) を使用(constructor 要らない)
• OnInit 廃止 → effect() で自動購読
• valueChanges を toSignal() で安全にシグナル化
• effect() 内で @Output() を emit
• FormGroup の型は NonNullable で安全に
⸻
child-form.component.ts(v20推奨版)
import { Component, Output, EventEmitter, effect, inject } from '@angular/core';
import { ReactiveFormsModule, FormBuilder, FormGroup } from '@angular/forms';
import { toSignal } from '@angular/core/rxjs-interop';
export type ChildFormValue = {
userName: string;
passWord: string;
};
@Component({
standalone: true,
selector: 'app-child-form',
imports: [ReactiveFormsModule],
template: <form [formGroup]="form"> <input formControlName="userName" placeholder="userName" /> <input formControlName="passWord" placeholder="passWord" /> </form>,
})
export class ChildFormComponent {
@Output() formChange = new EventEmitter();
private readonly fb = inject(FormBuilder);
// 型安全な FormGroup(NonNullable)
readonly form: FormGroup = this.fb.group({
userName: this.fb.nonNullable.control(''),
passWord: this.fb.nonNullable.control(''),
});
// valueChanges → signal 化(購読解除不要)
private readonly formValueSignal = toSignal(this.form.valueChanges, {
initialValue: this.form.getRawValue(),
});
constructor() {
// valueChanges の変化を自動検知して EventEmitter へ流す(OnInit不要)
effect(() => {
const v = this.formValueSignal();
this.formChange.emit(v);
});
}
}
⸻
✨ この書き方が「v20 推奨」な理由
✅ 1. constructor → inject() に置き換え
Angular v14〜で導入、v16〜推奨 → v20 はもはや標準。
✅ 2. ngOnInit を削除
valueChanges.subscribe() は手動 unsubscribe 必須。
toSignal() + effect() を使えば Angular が自動でライフサイクル管理する。
✅ 3. FormGroup の型安全性 UP
this.fb.nonNullable.control('')
により、string | null を避ける。
✅ 4. EventEmitter を発火する最小のパターン
effect() のみで OK
→ クリーンで subscription もない。
⸻
📌 完全に “今の Angular” の書き方
これが Angular v20〜v21 の公式推奨スタイルで、Signals との親和性が一番高い。
⸻
必要なら、これを使った「親側のシグナル同期コード」も書くよ
たとえば:
onFormChange(v: ChildFormValue) {
this.state.update(prev => ({ ...prev, form: v }));
}
みたいなやつ。