【ITニュース解説】The End of @Input() & @Output(): Angular 20’s Game-Changing Update
2025年09月22日に「Dev.to」が公開したITニュース「The End of @Input() & @Output(): Angular 20’s Game-Changing Update」について初心者にもわかりやすく解説しています。
ITニュース概要
Angular 20では、コンポーネント間のデータ受け渡しに用いた`@Input()`と`@Output()`が廃止される。代わりに`input()`、`output()`関数と、双方向バインディングを簡潔にする`model()`APIが導入され、コードがよりシンプルになる。これはAngularの新しいリアクティブな仕組みに沿った変更で、開発効率とパフォーマンスの向上が期待できる。
ITニュース解説
ウェブアプリケーションを開発する上で、画面を構成する小さな部品である「コンポーネント」間の連携は非常に重要な要素だ。人気のあるウェブフレームワークの一つであるAngularでは、これまで親となるコンポーネントから子となるコンポーネントへデータを渡し、逆に子から親へ何かを通知するために、「@Input()」と「@Output()」という特別な仕組みが長年使われてきた。これらは非常に強力な機能だったが、特にアプリケーションの規模が大きくなると、コードが複雑になりがちで、理解しにくい部分も少なくなかった。例えば、データを渡すための記述と、イベントを通知するための記述がそれぞれ独立して存在するため、同じデータを親と子で双方向にやり取りしたい場合には、さらに多くの記述が必要となり、コード量が増える傾向にあった。また、Angularが最近導入を進めている「Signals(シグナル)」という、データが変化した際に自動的に処理が実行される新しいリアクティブな仕組みと、従来の@Input()および@Output()の考え方には少し隔たりがあり、統一感が求められていた。
このような背景から、Angularのバージョン20では、コンポーネント間の連携方法に大きな変更が加えられた。この変更の目的は、コードをよりシンプルに、より分かりやすく、そしてAngularの新しいリアクティブな思想「Signals」と整合性の取れたものにすることにある。従来の@Input()や@Output()といった「デコレータ」と呼ばれる特殊な記法を用いる代わりに、今後は「input()」関数、「output()」関数、そして特に注目される「model()」関数という新しい方法が導入される。
まず、従来の「@Input()」の役割は、親コンポーネントから子コンポーネントへデータを渡すことだった。例えば、親コンポーネントが持つ「タイトル」という文字列を、子コンポーネントに表示させたい場合に利用した。これに対して「@Output()」は、子コンポーネントで発生した出来事(例えばボタンがクリックされたなど)を親コンポーネントに通知するために使われた。「EventEmitter」という仕組みと組み合わせて、子から親へメッセージを送るイメージだ。これらは非常に基本的なコンポーネント連携のパターンだが、データとイベントの送受信がそれぞれ別々の方法で定義され、特に大きなプロジェクトでは、どのデータがどこから来て、どこへ送られるのかを追跡するのが困難になることがあった。
Angular 20では、これらの機能が新しい関数として提供される。 「input()」関数は、従来の「@Input()」を置き換えるものだ。子コンポーネントで「title = input<string>();」のように記述するだけで、親から文字列を受け取ることができるようになる。これは以前の記述に比べて、より直接的で簡潔だ。子コンポーネント内でその値を使う際は「title()」のように関数として呼び出すことで、現在の値を取得できる。この「()」を付けて値を取得する形式は、AngularのSignalsの考え方に沿ったもので、値が変化したときに自動的に関連する部分が更新される、というSignalsの特徴を活かしている。
同様に、「output()」関数は、従来の「@Output()」を置き換えるものだ。子コンポーネントで「notify = output<string>();」のように記述し、親に通知したいタイミングで「notify.emit('メッセージ');」のように呼び出す。これも従来の「EventEmitter」を使う方式に比べて、よりシンプルに、そしてSignalsのエコシステムに自然に組み込まれる形だ。
ここで、実際のコード例を比較してみよう。従来のAngular 19では、子コンポーネントで「@Input() title!: string;」と「@Output() notifyParent = new EventEmitter<string>();」と記述していた。親コンポーネントでは「[title]="parentTitle"」でデータを渡し、「(notifyParent)="onNotify($event)"」でイベントを受け取っていた。これがAngular 20では、子コンポーネントで「title = input<string>();」と「notify = output<string>();」と記述するだけになる。親コンポーネント側での記述は大きく変わらないが、子コンポーネントの内部がよりすっきりと整理される。特に、子コンポーネントのテンプレート内で入力値を使う際には「{{ title() }}」のように関数として呼び出す点が、Signalsを使っていることを明確に示している。
そして、今回の更新で最も「ゲームチェンジャー」とされるのが、「model()」APIの導入だ。これは、親から子へデータを渡し、さらに子での変更を親へ即座に反映させるという「双方向バインディング」と呼ばれる仕組みを、これまでよりもはるかに簡単にする。従来のAngularでも双方向バインディングは可能だったが、それは@Input()と@Output()を組み合わせて、親側で特別な構文「[()]」を使うことで実現されていた。この内部では、実際には「値の入力」と「値変更の出力」という二つの動作が裏側で連携していたのだ。
model()関数を使うと、子コンポーネントで「title = model<string>('');」のように宣言するだけで、この双方向のやり取りが自動的に設定される。子コンポーネントのテンプレート内で入力フィールドの値に「[value]="title()"」とバインドし、入力イベントで「title.set($any($event.target).value)」のように値を更新すると、親コンポーネントの対応する値も同時に更新される。親コンポーネントでは、子コンポーネントを呼び出す際に「[(title)]="parentTitle"」という簡潔な記述をするだけで、親の「parentTitle」というデータと子の「title」というデータが常に同期されるようになる。これにより、データの流れが格段に追いやすくなり、コードの記述量も大幅に削減される。
このような変更は、単なる記述方法の変更にとどまらない。まず第一に、コードの記述量が減り(ボイラープレートの削減)、全体としてコードがより読みやすくなる。これにより、新しくプロジェクトに参加した開発者や、しばらくぶりにコードに触れる開発者でも、データの流れを理解しやすくなる。第二に、model()関数による双方向バインディングは、これまで複雑だった親子の状態管理を非常にシンプルにする。第三に、これらの新しい関数がAngularのSignalsと完全に連携するように設計されているため、Angularが目指す「リアクティブ・ファースト」なアーキテクチャへの移行が加速する。データが変更されたときに自動的に画面が更新される、といったリアクティブな挙動がより自然に、より効率的に実装できるようになるのだ。最終的には、開発者にとっての使いやすさ(開発体験)が向上し、アプリケーションのパフォーマンスにも良い影響が期待される。
結論として、Angular 20で導入されるinput()、output()、そしてmodel()関数は、Angularコンポーネント間の連携方法に大きな変革をもたらす。従来の@Input()や@Output()といったデコレータが不要になり、より簡潔で、よりモダンなJavaScriptの書き方に近い形でコンポーネント間のデータのやり取りを定義できるようになる。これは単にAPIが変わったというだけではなく、Angular全体がデータ変更に即座に反応する、より効率的で直感的な「リアクティブ」なエコシステムへと進化していくための重要な一歩となる。システムエンジニアを目指す上で、このようなフレームワークの進化を理解し、新しい書き方に慣れていくことは、効率的で保守性の高いアプリケーションを開発するために不可欠なスキルとなるだろう。