TypeScriptの特徴は何と言っても、
型にありますが、そんな型の中でも、
中心的な役割を占める、
プリミティブ型について、詳しく解説します。
文字ではなく、動画で観たい方は、
下記をご参考ください。
また、TypeScriptについては、
一通りの基礎文法を一動画で解説した、
総集編もありますので、
よろしければ、こちらもご参考ください。
プリミティブ型とは何か?
プリミティブとは、原始的なという意味を表す英単語で、
ここでは、最も基本的なデータ型を指します。
もっと、専門的に言うと、
オブジェクトではなく、メソッドやプロパティを持たないデータ型のこと指すようですね。
https://developer.mozilla.org/en-US/docs/Glossary/Primitive
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#data_property
オブジェクトは、プリミティブ以外のもので、
代表的なコードとしては、
const obj = {name: 'obj', age: 19} //jsの場合
const obj: { name: string, age: number} = {name: 'obj',age: 19} //tsの場合
のような感じです。
本記事はプリミティブ型の解説を主軸とするので、
オブジェクトには深入りしませんが、
オブジェクトは、nameやageのようなプロパティを持っています。
プロパティとは、上記のname(キー),'obj'(value)を合わせたものを指しています。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Working_with_Objects
つまり、プリミティブ型は、
平たく言うと、今まで使ってきた'hello'といった文字列や、
100といった数字型のように、その値しかないものと言えそうですね。
変数とかに定義された際に、
呼び出し方によって、値が変わる、
つまり複数の値が予め備わっていないものと考えれば概ね問題ないでしょう。
さて、そんなプリミティブ型は、全部で7種類存在します。
(本記事では、bitint型とシンボル型は、基礎からはやや外れるので割愛します。)
number型
これはその名の通り、
数値を表す型ですね。
const num = 5
ただ、TypeScript独特の仕様として、
number型には整数と小数の区別がありません。
下記では、整数しか定義していないが、
計算結果は、小数になっています。
const num1: number = 5
const num2: number = 8
const num3: number = 3
const ans: number = (num1 + num2) * num3 /2
console.log(ans) //19.5と表示される
これは、好き嫌いも分かれる部分かと思いますが、
静的型付け言語の型としては、ちょっと大雑把な印象があります。
以前、下記のようなツイートをしましたが、
同じ静的型付け言語のC++とかとはかなり異なっていますね。
それと、一般的に数値などは、
integerとかintという記法が多いのですが、
TypeScriptでは、numberとなっているので、
このあたりも微妙に混乱しますね。
string型
こちらも、基本的な型で、
'hello'のような文字列の型ですね。
文字列の作り方として、
""と''で囲うやり方があり、
基本的には大差ないかと思います。
書き方としては、下記のような感じです。
const hello: string = 'hello'
const hello1: string = "hello"
文字列の話に関連すると、
テンプレートリテラルという記法も存在するので、
そちらにも言及します。
テンプレートリテラル
これは、文字列の中に変数を入れることができるというメリットがある記法でして、
``とバッククオートで囲んで記述します。
Rubyとかでの式展開に近いものでして、
変数を埋め込みたい時に重宝します。
記法としては、下記のような感じです。
const str1: string = 'hello world'
const str2: string = 'HELLO WORLD'
console.log(`${str1}, ${str2}`)// "hello world, HELLO WORLD" と表示される
console.log('${str1}, str2') // "${str1}, str2"と表示される
//テンプレートリテラルでないと、変数名そのものが文字列になる。
このような変数名の埋め込みに関しては、
+演算子でも似たようなことができるので、
人によって、どちらの記法が良いかと好き嫌いが分かれることもあります。
ただ、個人的には、このテンプレートリテラルのほうが、
簡潔になるので、おすすめです。
boolean型
boolean型とは、真偽値のことで、
trueまたはfalseの2種類だけの値からなる型のことです。
const bool1: boolean = false
const bool2: boolean = true
trueとかfalseという概念は、
最初はピンとこないかもしれませんが、
命題の真か偽かと考えてもらえるとわかりやすいかもしれません。
プログラムでは、「こういう条件のときだけ、こういうことをしたい」みたいな場面が
たくさんあるのですが、まさに「こういう条件のとき」を表す際に、
「こういう条件 が真」→ こういう条件 === 真(true)というふうに表現して、
記述していきます。
boolean型は、こういうときに大活躍します。
以上のように、boolean型は条件分岐と交えて使用することがほとんで、
trueのときと、falseのときで実行したい処理を分けたいif文などでよく使われます。
真偽値変換の結果
実はわざわざtrueとかfalseと書かなくても、
どんな値も真偽値に変換されれば、この二種類のどちらかとなります。
そして、どういう値が、trueになりfalseになりというのは、
プログラミング言語ごとに異なるため、
これは、プログラミング言語の個性とみなされることが多いです。
条件分岐では、
値がそのまま入れられることも多いです。
if (0) console.log(0) //0はfalseなので実行されない。
if (1) console.log(1) //1はtrueなので実行される。
if ('hello') //'hello'はtrueなので実行される
if (num1 < num2) //num1の方がnum2未満なら実行され、そうでないと実行されない条件分岐
ちなみに、falseに判定されるものは、 false, ""(空文字列), 0, NaN, null, undefinedで、
それ以外はすべてtrueと判定される。
多くの言語は、0をfalseと判定していますが、
例えばRubyとかは、0もtrueと判定しており、
Rubyにおける、falseは、nilとfalseだけというシンプルさ。
プログラミング言語によって、かなり違いますね。
ちなみに、Rubyにも興味がある方は、
こちらの記事で紹介しているので、
ご参考ください。
-
参考【Rubyすべてがオブジェクト】変数と真偽値/論理演算子/コメント
本記事は、Rubyの基礎文法である、変数や真偽値、論理演算子に触れると同時に、「すべてがオブジェクト」というRubyの特徴的な思想についても解説します。 この思想は、Rubyの文法の根幹になっているの ...
続きを見る
null型とundefined型
null型は、その名のとおり、
nullという値だけをもつ型です。
プログラムでは値が存在しないというものを、
このようなnullとかで表すことが多いのですが、
バグの原因になったりするので、
nullについては、慎重に扱う必要があります。
(※TypeScriptの場合、null安全のような議論もあるので、
一般的なnullに対するイメージとは必ずしも一致しないこともありますが、
ここではややこしくなるので、そこには言及しません)
ちなみに、0とかとは何が違うのかというと、
0は、number型で値が存在します。
その証拠に、0 + 1 = 1というように、
0に足したりできます。
これに対して、nullは、値が存在しないので、
上記のようなことはできません。
イメージとしては、0は、0という存在があるけど、
nullは存在自体がないことを表す概念という感じです。
ややこしいですね。
最初のうちはピンとこないかもしれませんが、
要するに、値が存在しないものと思っていただければ大丈夫です。
undefined型も似たようなもので、
undefinedという値だけを持つ型です。
const num: null = null
const num2: undefined = undefined
これらは、データがないということを表すものです。
他のRubyなどの言語では、
こういったデータがないという型は、
nilなどのように一種類のことが多いのですが、
TypeScriptでは、このように二種類存在します。
これは、TypeScriptやJavaScriptの大きな特徴なのですが、
一体どちらを使うべきなのかというと、
個人的にはundefinedの方が良いのかと思います。
undefinedは、オプショナルプロパティなどに出現するので、
null型よりは、遭遇機会も多く、下手なバグに遭遇しにくい印象があります。
(ただ、チームの方針によるので、もう正直どちらでも良いと思います。
どちらが絶対にだめという類のものではないです。)
基本的に、こういった型は、自分で定義するものではなく、
メソッドや関数などの返り値がデータがない、
null型とかだった場合に、別の処理を記述するといったようにして、
null型を減らすよう努める類のものです。
なので、この2つが出てきたら、
データがないと捉えれば問題ないです。
ラッパーオブジェクト
プリミティブ型は、オブジェクトと違って、
メソッドを持ちません。
しかし、あたかもメソッドを持つかのように振る舞います。
例えば、"hello"というのは、
文字列でプリミティブ型なので、
本来メソッドを持ちません。
けれども、下記のようにincludesメソッドを実行できます。
"hello".includes("h")
これは、"hello"という文字列のラッパ−オブジェクト,Stringに変換され、
そのラッパーオブジェクト経由でメソッドが呼び出せれているので、
あたかもオブジェクトのように振る舞っているということです。
ラッパーオブジェクトとは、
そのプリミティブ型の大本のクラスのインスタンスですね。
型注釈に振る型と思っていただければ大丈夫です。
すなわち、
new String("hello").includes("h")
と同義です。
typeofを使うとわかるのですが、
"hello"は文字列なのに対し、
new String("hello")は
オブジェクトになります。
const str1 = new String("hello")
const str2 = "hello"
console.log(typeof str1); // object
console.log(typeof str2); // string
メソッドはオブジェクトでないと、呼び出せないのに、
プリミティブ型からも呼び出せるように見えるのは、こういう仕掛けがあるからです。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
ちなみに、数値型は、Number、真偽値は、Booleanといった
ラッパーオブジェクトがあります。
詳細は、下記に書かれてあります。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
なぜ、長々とこんなことを説明したのかというと、
冒頭でプリミティブ型は、プロパティやメソッドを持たないと言った意味が、
上記のラッパーオブジェクトに関わっているからです。
プリミティブ型とは何かという定義に対し、
ドキュメントもラッパーオブジェクトに言及して説明しています。
これで下記のドキュメントで言っている意味がわかるようになるはずです。
https://developer.mozilla.org/en-US/docs/Glossary/Primitive
プリミティブ型は、nullとundefined以外、
ラッパーオブジェクトを持っています。
それはすなわち、ラッパーオブジェクトがないと、
メソッドなどを実行できないからです。
nullとundefinedには当てはまらないが、
この2つはやや特殊なのでプリミティブ型とは何かという問いに対し、
対応するラッパーオブジェクトを持ち、
メソッドを実行する際、それに変換されるものと考えた方が、
わかりやすいかもしれないですね。