一般社団法人 全国個人事業主支援協会

COLUMN コラム

  • VueのDeepReadonlyについて

VueのDeepReadonly型はImmutableな値を示す型です。

しかしDeepReadonly型は少し問題があり、例えばDeepReadonly<Ref<T>>型に対して普通のRef<T>が代入できてしまいます。これはTypeScriptが構造的型付けという手法を取っているために発生する問題です。

具体的に言うと、DeepReadonly<Ref<T>>はRef<T>とプロパティ構造が一致しているため、コンパイラは代入を許してしまいます。表面的には「readonly」とついているのに、実際には.valueを書き換えることができてしまうのです。つまり型レベルでImmutableを保証しているつもりでも、実際には完全には守られないというギャップが生じます。

この挙動はVueの型定義だけでなく、TypeScript自体の設計に起因しています。TypeScriptは「構造的型付け」を採用しており、名前や宣言の違いではなく「型の形」が一致するかどうかで代入可能性を判断します。そのためDeepReadonly<Ref<T>>とRef<T>の間に本質的な違いがないとみなされ、結果的に代入が許されてしまうのです。

では、どう対処すべきでしょうか。一つの有効な方法は「ブランド型(brand type)」を使うことです。ブランド型とは、通常の型に“識別用の印”を付与することで、構造的に同じ型であっても別物として扱わせる仕組みです。TypeScriptは構造的型付けを採用しているためにDeepReadonly<Ref<T>>Ref<T>を同一視してしまいますが、ブランドを導入すれば「これは通常のRefとは異なる特別な型だ」とコンパイラに区別させることができます。

これを利用することで型レベルで保証できます。

The following two tabs change content below.

中山 祐輔

最新記事 by 中山 祐輔 (全て見る)

この記事をシェアする

  • Twitterでシェア
  • Facebookでシェア
  • LINEでシェア