Marginalia

Angular: 属性値からの型変換が書きやすくなるinput transforms

Angular v16.0が出て間もないが、なかなか面白そうな機能追加が進んでいる。

端的には、次のようなコードが書けるようになる。テンプレートでのプロパティバインディングとしては string 型で受け取りつつも、受け取った内部では number 型のプロパティとして保持するために、型変換を挟んでいる。

// foo.directive.ts
@Directive()
export class Foo {
  @Input({transform: (incomingValue: string) => parseInt(incomingValue)}) value: number;
}

これと同様のことはこれまで Setterプロパティと Angular CDK の coercion ユーティリティが解決してきた。

import { NumberInput, coerceNumberProperty } from '@angular/cdk/coercion';

@Directive()
export class Foo {
  #value: number;

  @Input() 
  set value(v: NumberInput) {
    this.#value = coerceNumberProperty(v);
  }
}

なぜこのような型変換が必要かというと、HTMLの仕様上、 [prop] というように [] を伴わない属性値の指定では、それをインプットプロパティが受け取る時に stringundefined にしかならないからだ。

<some [disabled]="true" /> // boolean

<some disabled="true" />   // string

<some disabled />          // undefined

特に問題になるのは disabled のようにboolean型のインプットとしてもサポートしつつ、その属性がついているだけでも true 扱いにするような、HTML標準の属性に振る舞いを合わせるときだ。これはいままではCDKを使って次のように書いていた。

import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';

@Directive()
export class Foo {
  #disabled = false;

  @Input() 
  set disabled(v: BooleanInput) {
    this.#disabled = coerceBooleanProperty(v);
  }
  get disabled() {
    return this.#disabled;
  }
}

これが冒頭で紹介した新しい書き方だと次のように書けそうだ。

import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';

@Directive()
export class Foo {
  @Input({ transform: coerceBooleanProperty }) disabled = false;
}

おそらく順当に進めば v16.1 で導入されるのではなかろうか?汎用性の高いコンポーネントやディレクティブを作る上ではボイラープレートコードを減らしてくれそうなので、期待したい。

参考リンク