はじめに
最近、Next.js + TypeScriptを使ってフロントエンドの開発をしています。TypeScriptに関して興味はあったものの、実際に開発を行うまでは「JavaScriptを静的型付けに拡張した言語」という程度の知識しかありませんでした。JavaScriptはある程度わかるので、TypeScriptはそれに静的型付けが加わっただけなのだから、簡単に習得できるだろうと思っていました。
上記のような軽い気持ちでNext.js + TypeScriptの開発を始めたわけですが、VSCodeによるTypeScriptの静的解析がかなりしっかりしているので、結構な頻度で静的解析エラーに遭遇しました。普段の業務では動的型付け言語であるRuby (Ruby on Rails) を使っているので、静的型付け言語を使うのは随分久しぶりになります。
本記事では、今回私が遭遇した「代入式の左辺には、省略可能なプロパティ アクセスを指定できません。」という静的解析エラーについて記述します。
代入式の左辺では Optional Chaining (Optional Parameters) が使えない
例えば、以下のようなコードがあるとします。
type User = {
name: string
};
let user: User | undefined
user?.name = 'Sakai Kotaro';
user
は宣言時にUser | undefined
(User
型または不定)と型指定しています。user
の末尾に?
を付けることで、不定の可能性がある変数を安全に呼び出すことができるようになります。Rubyにおける&
(ぼっち演算子)と同じです。JavaScriptではOptional Chaining、TypeScriptではOptional Parametersと呼びます。
しかし、Optional Chaining (Optional Parameters) は代入式の左辺で使うことができません。上記のように代入式の左辺にOptional Chaining (Optional Parameters) を使った変数を記述すると、以下の静的解析エラーが発生します。
Error: The left-hand side of an assignment expression may not be an optional property access. ts(2779)
代入式の左辺には、省略可能なプロパティ アクセスを指定できません。ts(2779)
仮にuser
の値がundefined
の場合、undefined
に対してname
を呼び出すことはできないので、静的解析エラーとなります。
不定の可能性がある変数に代入する方法
逆説的ですが、変数が不定である可能性がなくなればOptional Chaining (Optional Parameters) を使う必要はなくなります。代入の前にif
ステートメントで変数が不定でないかを判定します。
if (user) {
user.name = 'Sakai Kotaro';
}
// or
if (typeof user === 'object') {
user.name = 'Sakai Kotaro';
}
// or
if (user != undefined) {
user.name = 'Sakai Kotaro';
}
if
ステートメントで変数の型を判定することを型ガード (type gards) と呼びます。
以下のように記述しても静的解析エラーを回避することができます。
user!.name = 'Sakai Kotaro';
!
はNon-null assertion operatorと呼び、変数末尾に付けることで変数が不定でないことを明示します。
Non-null assertion operatorは変数が不定でないことを保証するものではありません。そのため、変数が不定であった場合に代入式が実行されると、ランタイムエラーが発生するので注意が必要です。静的解析エラーを回避するためだけにNon-null assertion operatorを使うのは非常に危険です。
まとめ
「代入式の左辺には、省略可能なプロパティ アクセスを指定できません。」という静的解析エラーの原因と回避方法について記述しました。こういった静的解析エラーを丁寧に解消していくと、実行して初めて発生するエラーに遭遇する可能性が低くなっていきます。静的型付け言語のメリットを感じられた気がします。
現在、Next.js + TypeScript + Ruby on Rails (API)という構成で開発を行っているため、これからNext.jsやTypeScriptの記事をどんどん書いていく予定です。