フロントエンド

【TypeScriptの変数】let/constと変数として使えないもの

TypeScript変数完全解説

reisuta

Webエンジニア | 20代中盤 | 大学時代はGmailすら知らないIT音痴でプログラミングとは無縁の生活を送る → 独学でプログラミングを学ぶ → Web系受託開発企業にエンジニアとして就職 → Web系自社サービス企業に転職 | 実務未経験の頃からVimを愛好しており、仕事でもプライベートでも開発はVimとTmuxを使っているので、VSCodeに疎いのが最近の悩み。何だかんだでやっぱりRubyが好き。

TS Playground

TS Playgroundは、
TypeScriptを試すことができるサンドバッグ的環境。

通常、プログラミング言語の学習などをする際は、
自分のPCに実行環境を構築する必要があるのですが、
この作業が割りと最初の関門だったりします。

なので、クラウド上で、手軽にTypeScriptを試すことができると、
便利なわけですが、TS playgroundは、それに該当します。

こんな感じです。

このようなplaygroundは、
TypeScriptに限らず、様々な言語にあり、
有名所でいうと、Rust Playgroundでしょうか。

静的型付け言語の場合、
コンパイルという作業が必要になるのですが、
たかが文法の学習にそのような実行環境を作るのは、
面倒なときもあります。

TypeScriptも静的型付け言語なので、
TypeScriptの文法を試す際、
playgroundを使うと手軽で便利かなと思うので、
最初にご紹介します。

https://www.typescriptlang.org/play

変数とは?

変数とは、
よく箱に例えられることが多いので、
値などを格納することができる名付けの役割を果たします。

例えば、TypeScriptだと下記のように変数を定義するのですが、

const box = '何かが入っている箱です'

この場合、boxというの変数名で、
箱のような感じです。

以降、このboxを呼び出すと、
値が'何かが入っている箱です'に書き換えられて使用できるので、
boxというのは、ある種の名付けのようになっているという感じです。

さて、そもそも素朴な疑問としてなぜ箱が必要なのか思うかもしれません。

変数は確かに値が入っている箱ではありますが、
そうした箱を使う理由は、先述のように
値などに名前をつけたいからと考えれば大丈夫です。

例えば、
ラーメン屋の売上が100000円で、
曜日によって、
ラーメン屋の売上から1000円引いたり、
300円引いたりと、売上額に対して色々計算をする場合、
変数を使わないと、

console.log(100000 - 1000)
console.log(100000 - 300)

のように、パット見上の数字が何を表しているのかよくわかりません。

そこで変数を使って、
それぞれをいわゆる箱に入れると、
変数名に好きな名前をつけることができるので、
(※変数名にできないものもあるがそれは後ほど解説します。)

const uriage = 100000
console.log(uriage - 300)
console.log(uriage -1000)

というふうすれば、売上から何かを引いているということがわかります。

実際は、上記のような処理の際は関数を使うのがいいのですが、
(関数も名前をつけられる)
変数の名付けの特徴としては、上記のような感じです。

変数の利点はこれ以外にも色々ありますが、
一旦、名付け機能が強力だからという印象で問題ありません。

ちなみにですが、変数の名付けは、とても奥が深く、
難しいものです。

というのも、上記のコードで、
uriageの変数名が下記に変わっていたとするとどうでしょう?

const sio-ramen = 1000000
console.log(sio-ramen - 100)
console.l0g(sio-ramen - 1000)

あれ、塩ラーメンって、1000000円もするの?
どんだけ高級なんだよ!って感じですよね。

ただ、これはsio-ramenという名付けが悪くて、
実際の処理は、uriageから引いている処理です。

ただ、上記のコードだけ見たら、
「塩ラーメンの値段から何か引いているんだな」と
読み取れます。

つまり、変数名は、自由に命名ができるにも関わらず、
そのままの意味で読み取られてしまうので、
嘘の変数名など書いてしまうと、一気にコードが意味不明になります。

さすがに、上記のような命名はしないかもしれませんが、
例えば、

const uriage1 = 100000
const uriage2 = 100000
console.log(uriage1 - 300)
console.log(uriage1 -10000

のような感じだとどうでしょう?

uriage1とuriage2どう違うねん!って思いませんでした?

ただ、こういう命名は最初のうちは
意外とやってしまいがちです。

「いや、自分はわかりますよ」って思うかもしれませんが、
プログラム開発においては、それではだめで、
他の人が読んでも誤解なく受け取ってもらえるかを
意識する必要があります。

コーディングの意図がわからない、他人が上記のコードを読んだら、
uriage1とuriage2の違いはわかりませんし、
なぜ、uriage1からしか引いていないのかもわかりません。

つまり、変数名にコーディングの意図を語らせる必要があるのですが、
命名な自由なだけ、そのあたりは腕の見せどころになります。

変数の名付けが難しく、奥深い理由はこのような感じです。

TypeScriptの変数

TypeScriptのベースは、
JavaScriptなので、型以外は、
基本的に変数宣言のやり方は同じです。

とはいっても、
JavaScriptがあんま良く知らんっていう人も
いるかと思います。

その場合でも、いきなりTypeScriptから勉強しても
良いかと思います。

JavaScriptは、TypeScriptで型を振らない状態のようなものなので、
TypeScriptの基本文法を学んでおけば、
JavaScriptも基本的な部分は十分でしょう。

さて、ではそんなTypeScriptの変数宣言ですが、
型をつけないで、変数宣言をすることもできるので、
下記のようにJavaScriptと同じ文法で変数定義もできます。

下記は、JavaScriptでもあり、TypeScriptでもあるコードです。

const hello = 'Hello'
console.log(hello) // 'Hello'と表示される

ちなみに、
一行コメントは、//で行い、 複数行コメントは、//で行います

これをTypeScriptにすると、

const hello: string = 'Hello'
console.log(hello)

というふうに型をつけることができます。

Helloは、文字列なので、
stringを型として指定します。

ちなみに、上記のような場合は、
型推論がきくはずなので、
stringの型注釈をする必要もないかもしれません。

https://typescriptbook.jp/reference/values-types-variables/type-inference

ただ、型注釈はある種のドキュメント(コードの可読性を上げる)の役割も果たせるので、
基本的には型を振っておいても損はないかなと思います。

ちなみに、下記のようにany型というのを振ることもできますが、
これは、型注釈を無視して、TypeScriptの利点を放棄することに等しいので、
実質的にはJavaScriptと同等です。

const hello: any = 'Hello'
console.log(hello)

上記の場合は、any型を振らなければ、
型推論がきくのに、わざわざany型にしてそのメリットを放棄しているので、
通常ならありえないコードですね。

any型は、JavaScriptからTypeScriptに移行するために
暫定的に使うぐらいでしょうか。

ちなみに、ESLintとかでも、
any型があると警告が出たりします。

こういった型の詳細については、
下記の記事もご参考ください。

TypeScriptプリミティブ型
参考【TypeScript基礎】プリミティブ型、基本的な型の種類について

TypeScriptの特徴は何と言っても、型にありますが、そんな型の中でも、中心的な役割を占める、プリミティブ型について、詳しく解説します。 文字ではなく、動画で観たい方は、下記をご参考ください。 h ...

続きを見る

変数名としてつかえないもの

さて、そんな変数ですが、
何でも好きな名前をつければいいというわけでもありません。

まず予約語は変数名には使えません。
予約語とは、ifやforなど、TypeScriptのなかで予め用意されているものです。

基本的には、JavaScriptの予約語と変わらないはずです。
ここにJavaScriptの予約語が書かれています。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Lexical_grammar

ただ、変数の名付けは、基本的に他のプログラマーがわかるような変数にするため、
正直予約語と衝突することはあまりありません。
(予約語を変数名に使っている時点で変数名としては良く傾向があるので)

ただ、例えば教育関連のシステムで、
学校のクラスの変数名を使いたいときは、
予約後で衝突するので、衝突したからと悪いともかぎりません。

こういう場合は、変数名を考えるのが大変ですが、
別のものにする必要があります。

JavaScriptの話ではありませんが、
以前、Ruby on Railsを使用している際、
テーブルのカラムにsequece(順番)というものが有りましたが、
これがライブラリのFactory botのメソッドと衝突するということが有りました。

予約後の衝突というわけでもありませんが、
衝突すると、エラーになってしまうので、
避けましょう。

変数名の話に戻りますが、
一応、日本語も変数名にすることは、
可能っちゃ可能です。

けれども、基本的に変数名に日本語を使用することはありません。

そもそもコンピュータと日本語の相性はあまり良くなく、
文字コード関連で余計なエラーを招く可能性があるので、
日本語じゃなきゃだめという強い理由がないと変数名に採用するのは、
避けるべきかなと思います。

数字に関しては、先頭以外であれば、
変数名に含めても問題ありません。

記号系に関しては、基本的にNGだが、
_とかは比較的よく使われます。

変数の命名規則に、
パスカルケースや、ケバブケース、スネークケースなどありますが、
_などは、スネークケースとかで用いられますね。

TypeScriptの場合、スネークケースが採用されるケースは
殆どないと思いますが、Rubyとかだとスネークケースで記載することが
増えてきます。

https://typescript-jp.gitbook.io/deep-dive/styleguide

TypeScriptの変数名の良い例を紹介すると、

const greeting = 'hello'
const uriage1 = 10000
const kyounoUriage = 1000

反対に変数名の悪い例を紹介すると、

const あいさつ = 'hello' //エラーにはならない
const 1uriage = 1000
const if = 1999 //予約語を変数名にしている
const kyouno uriage = 1000 //変数名に空白が入っている
const kyouno_uriage = 1000 //エラーにはならないが、JavaScriptの変数でスネークケースはスタイルガイド的に良くない

のような感じになるかなと思います。

まあ、正直な話、
バックエンドRuby、フロントエンドJavaScriptの構成とかだと、
api側の変数の命名規則に併せて、フロント側でもスネークケースで受け取るみたいなことは、
全然あるかなとも思いますので、スネークケースについては、
一概に悪いとも断定できませんが。

変数に型を与える

さて、上記までの話は、
TypeScriptというより、
JavaScript寄りの話でしたが、
TypeScriptの特徴はなんといっても、型にあります。

先程、ちらっと触れましたが、
TypeScriptは変数に型注釈を加えて書きます。

const greet: string = 'hello'

上記の: stringの部分が型注釈です。

stringというのは、文字列のことで、
変数greetに代入されているのは、
'hello'という文字列です。

なので、この場合は問題ないコードです。

const greet: stringと書いた時点で、
greetという変数にはstring型しかいれることができないというのが、 上記のコードの意味です。

試しにstring型以外を入れてみましょう。

const greet: string = 100

すると、

Type 'number' is not assignable to type 'string'.

となります。

これは、100がnumber型なのに対し、
greetという変数がstring型になっているので、
型が一致しないよというコンパイルエラーです。

「エラーが出るんだったら、
JavaScriptのほうがいいんじゃね?」
って思うかもしれませんが、
実はそうではないのです。

型があることによる恩恵は、偉大ということを解説します。

型の恩恵

先程変数は箱と言ったように、
まさしく、変数は処理されたあとの値を待ち受ける箱のように使うことがあるでしょう。

その際、JavaScriptだと、型を宣言することはできないので、
箱は渡された値をそのまま入れるしかありません。

イメージとしては、毒を渡されても、
それが毒ですとは教えてくれず、
黙って箱の中にしまってしまうのが、 JavaScriptです。

おとなしい人が、嫌といえずに溜め込んでしまって、
最後に爆発してしまうのに似ているかと思います。
(この場合、爆発はJavaScriptの場合だと本番コードでの
エラーでインシデントになることですかね。)

それに対して、TypeScriptは待ち受ける箱に予め型をつけることができるので、
渡されてきた値が型と違っていれば、違うよというコンパイルエラーを出してくれます。

すなわち、毒を渡されても、 それが毒です、受け付けられませんとエラーを出してくれるのが、 TypeScriptです。
本番コードに上げる前に、まずい部分を指摘してくれるので、
本番でのインシデントの軽減に一役かってくれているという感じです。

コンパイルエラーと言われると身構えてしまいますが、
要は不適切な値を事前に弾いてくれているため、
非常にありがたい代物と思っていただければ大丈夫です。

JavaScriptとかだと、毒が全身に回って、死亡するまで
(ソフトウェア的には、バグが複雑化して手がつけられなくなるまで)
気づかない恐ろしさがあるともいえます。

まあ、何が言いたかったのかというと、
とりあえず、コンパイルエラーは喜ぼうっていうことです。

よく、「エラーが怖くなくなる本」みたいな書籍を
見かけることがありますが、
ああいう本の趣旨も、だいたいこのような感じなのかなと思っています。

エラーは親切に教えてくれているんですよ(笑)

letとconst

上記までの具体例では、
変数宣言の際、基本的にconstを使用してきました。

これに加えて、letというものもあります。
(varというのもありますが、非推奨なので紹介しません。
昔のレガシーコードでは遭遇することもあるかもしれませんが、
基本的に使うべきではありません。)

let greet: string = 'hello'

書き方は、constの部分をletに置き換えるだけです。

letとconstの違いは再代入可能かどうかです。

const hello = 'hello'
hello = 'namasute' //Cannot assign to 'hello' because it is a constant.というエラーにな

let greet = 'hello'
greet = 'namasute' //エラーなし
console.log(greet) // namasuteと表示される

再代入できるletの方が柔軟で良さげと思うかもしれませんが、 可能な限りletを使うのは避けるべきです。

なぜなら、再代入可能ということは、
最初に宣言された値とは変わる可能性があるからです。

先程の、TypeScriptとJavaScriptの話に似ていますね(笑)

つまり、letで宣言された変数の場合、
いま現時点でletの変数になんの値が入っているのか正しい状態なのかを
判断しなければなりません。

let greet = 'hello'
greet = 'hello1'
let greet1 = 'hello1'
greet = 'hello'
greet1 = 'hello'
greet = greet1
greet = greet  + greet1
greet = greet + greet
console.log(greet)

実際には、こんなコードは嫌がらせのとき以外は書かないが、
文法上は、こういうコードも許してしまうということになります。

console.logで何が出力されるのか、
いちいち処理を追って行かないとよくわかりません。

つまり、letの使用は読み手に負担を与える可能性があるということです。

そのため、ifやforなどの複雑なロジックで、
やむをえずletを使うしかない場面以外は基本はletを使わないようにするべきかなと思います。

入門書とかのサンプルコードを見ると、
letのほうが使用頻度が多いので、
letを使っておけばいいだろうみたいない思う方もいるかもしれませんが、
上記の理由で、基本はconstです。

letで書いてしまったら、なんとかしてconstに書き換えできないか、
コードを見直すサインともいえるかもしれないですね。

  • この記事を書いた人
  • 最新記事

reisuta

Webエンジニア | 20代中盤 | 大学時代はGmailすら知らないIT音痴でプログラミングとは無縁の生活を送る → 独学でプログラミングを学ぶ → Web系受託開発企業にエンジニアとして就職 → Web系自社サービス企業に転職 | 実務未経験の頃からVimを愛好しており、仕事でもプライベートでも開発はVimとTmuxを使っているので、VSCodeに疎いのが最近の悩み。何だかんだでやっぱりRubyが好き。

おすすめ記事はこちら

Vim/Neovimプラグイン 1

プラグインをどれだけ入れるかは、その人の思想なども関係するので、一概にこれがいいというのはないかもしれません。 プラグインを全く入れない人もいれば、100個以上入れる人もいます。 ただそれでも、これだ ...

VimとNeovimの比較 2

本記事では、VimとNeovimの違いについて、解説します。 VimとNeovimの違いについては、普段頻繁にVimなどを使う方でなければ、正直、あまり気にしなくてもいいかなと思います。 ただ、Vim ...

Ruby変数やすべてがオブジェクトについて 3

本記事は、Rubyの基礎文法である、変数や真偽値、論理演算子に触れると同時に、「すべてがオブジェクト」というRubyの特徴的な思想についても解説します。 この思想は、Rubyの文法の根幹になっているの ...

4

エンジニアにおすすめの技術書 書籍学習は、エンジニアの嗜みみたいなところがありますが、 良書というものは、意外とそこまで多くもありません。 そこで本記事では「技術書マニアの筆者が厳選した技術書20選」 ...

5

エンジニアになるには? プログラミングは、専門性が高く自分一人で勉強するのが大変に感じることも多いですよね。 そこで本記事では「おすすめのプログラミングスクール5選」を特徴と、現役エンジニア目線で優れ ...

-フロントエンド