TypeScript: as const [アウトプット全くしてこなかったのでアウトプットする001]


自分は「プログラミング業務外でやりたくない期間」と「プログラミング業務外でもめっちゃやりたい期間」が1年の中で交互に来るのですが、今は割とやりたくなってきているのでいつまで続くかわかりませんがアウトプット記事を書いていきます。

何もつけない場合

const cawauchi = {
  height: 176,
  weight: 73.5,
  from: "栃木"
};

上記の場合以下で値を代入可能です。

cawauchi.height = 122;

constアサーション

const cawauchi = {
  height: 176,
  weight: 73.5,
  from: "栃木"
} as const;

readonlyの場合以下で値を変えようとするとエラーを出してくれます。

cawauchi.height = 122;

可能な限りプロパティにreadonlyを付けましょう。特に、関数が引数としてオブジェクトを受け取る場合はreadonlyの使用を徹底しましょう。
これは、関数がプロパティを書き換えるかどうかを型の上にドキュメント化し、さらにTypeScriptによるチェックを受けられるという意味があります。

代入をしたりしない場合、可能な限りreadonlyをつけるのが良いとありました。

逆に言えば、渡されたオブジェクトを変更しない関数の場合は引数のオブジェクトの型に積極的にreadonlyを付けるべきだということです。これにより、その関数を使う人は、関数の中身を見なくても型情報を見るだけで「この関数は渡されたオブジェクトを破壊しない」という安心感を(TypeScriptコンパイラによる保証付きで)得ることができます。
さらに言えば、readonlyという道具が存在するにも関わらずreadonlyが付いていないということは、そのプロパティを勝手に変更するかもしれないよという意思表示だということです。これは「変数宣言にconstではなくletをわざわざ使うということはその変数をあとから変更するという意思表示である」という考え方と同じです。

なるほどなるほど.....

この問題を低減させる方法のひとつとして、Readonly組み込み型を用いる方法があります。これは、Tの全てのプロパティにreadonlyを付加して得られる型です。これなら型定義の際に全てのプロパティにreadonlyと書く必要がなくお手軽です。活用しましょう。

type FooBarBaz = {
  foo: number;
  bar: number;
  baz: number;
}

function sum(obj: Readonly<FooBarBaz>) {
  obj.foo = 999; // これはコンパイルエラー
  return obj.foo + obj.bar + obj.baz;
}

おおお....!

参考

強くなりたい!!!!!!!!