投稿日:2020年11月15日
TypeScriptは型付き言語であるため、型への理解が非常に重要になります。この記事ではTypeScriptの中の基本の型について解説しています。
Any型はどんな値でも受け入れることのできる型です。
それだけ聞くとなんとなく便利な型に思えるかも知れませんが、
この型の使用はできる限り避け、もし使用する場合は特に注意してください。
何故注意が必要なのか、例として以下のコードがあるとします。
function hello(greeting: any){
console.log(greeting.greet());
}
hello("Hello World");
このコード見るからにバグがあります。
hello()という関数に"Hello World"という文字列を渡しているのですが、
この関数は内部で渡された引数のgreet()という関数を呼び出しています。
文字列はそんな関数をもっていない!!
トランスパイル時にエラーを出力してくれるかと思いきや、なんと問題なく通ってしまいます。
$ tsc any_sample.ts
ではいつエラーが出力されるのかというと、実行時なのです。
$ node any_sample.js
/home/ogihara/ts_sample/any_sample.js:2
console.log(greeting.greet());
^
TypeError: greeting.greet is not a function
at hello (/home/ogihara/ts_sample/any_sample.js:2:26)
at Object.<anonymous> (/home/ogihara/ts_sample/any_sample.js:4:1)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)
これではJSをそのまま書いていたのと変わりません。
思わぬバグを生まないように、できる限り使用は避けましょう。
もし使う場合でも型推論によるAnyの使用は絶対に避けましょう。
TSConfigでは型推論によるAnyの使用を禁止する設定(【TypeScript】TSConfigで型推論のAny型を禁止)もあるのでこの設定を使っても良いでしょう。
Unknown型はAny型と非常によく似ていますが、Any型から危険性を取り払った様な優秀な特性をもちます。
あらかじめ型の指定ができないようなコードの場合にはこのUnkown型を使用しましょう。
Unknown型はAny型と同じように、全ての型を受け入れることができます。
しかし、Any型の違いその値のタイプを特定するまでは値を使用することができません。
例えば以下のコード
function helloWorld(greeting: unknown){
console.log(greeting.trim());
}
helloWorld(" Hello World ");
helloWorld(10);
これはトランスパイル時点でエラーになります。
ヤバイコードなのでエラーになってくれてOK!!
$ tsc unknown.ts
unknown.ts:2:26 - error TS2339: Property 'trim' does not exist on type 'unknown'.
2 console.log(greeting.trim());
~~~~
Found 1 error.
このコードをトランスパイルを正しく通すには型のチェックを入れます。
function helloWorld(greeting: unknown){
if(typeof greeting == "string"){ // タイプを特定しないと使用できない
console.log(greeting.trim());
}
}
helloWorld(" Hello World ");
helloWorld(10);
関数helloWorld()は引数としては全ての型の値を受け入れますが、内部のString型を前提としたコードは引数の型がString型の場合のみ動作するため、エラーを発生させる危険性がありません。
$ tsc unknown.ts
$ node unknown.js
Hello World
ちなみにTypeScriptの型推論がunknown型を推論することはありません。
Boolean型はtrue(真)とfalse(偽)の2つの値をとることのできる型です。
function checkBoolean(value: boolean){
if(value == true){ // 値を比較
console.log("This value is true");
}else{
console.log("This value is false");
}
}
let value: boolean = true;
checkBoolean(value);
checkBoolean(!value); // 値の否定を渡す
$ tsc boolean.ts
$ node boolean.js
This value is true
This value is false
ただしBoolean型はリテラル型をサポートしている点には少し注意が必要です。
リテラル型は一つの値のみを受け入れ、それ以外の値の受け入れを拒否する型のことです。
Boolean型でリテラル型を使用する方法は型宣言でtrue、またはfalseを指定する方法とconstを使用する方法の2つあります。
let a: true = true;
let b: false = false;
const c: boolean = true;
リテラル型で指定した場合、その値以外の値をいれようとするとエラーになります。
let a: true = true;
let b: false = false;
const c: boolean = true;
a = !a;
b = !b;
c = !c;
$ tsc boolean_literal.ts
boolean_literal.ts:6:1 - error TS2322: Type 'boolean' is not assignable to type 'true'.
6 a = !a;
~
boolean_literal.ts:7:1 - error TS2322: Type 'true' is not assignable to type 'false'.
7 b = !b;
~
boolean_literal.ts:8:1 - error TS2588: Cannot assign to 'c' because it is a constant.
8 c = !c;
~
Found 3 errors.
Number型は全ての数値型(整数、浮動小数点数、無限大、非数)の集まりです。
基本的な四則演算や比較などを行う事ができます。
let a = 1234;
let b: number = 100;
let c = 60.00;
console.log(a + c);
Numberもリテラル型をサポートしています。
以下の様な書き方で特定の値に限定した変数の定義が可能です。
const a = 1234;
let b: 100 = 100;
number型では非常に大きな値を扱う場合に丸め誤差というものが発生してしまう場合があります。
Number型が正しく扱える値の最大値、最小値はNumber.MAX_SAFE_INTEGERとNumber.MIN_SAFE_INTEGERに定義されています。
この定義以上の値を使用する場合には注意しましょう。
let a = Number.MAX_SAFE_INTEGER;
console.log(a);
a = a + 2;
console.log(a);
$ tsc number_sample.ts
$ node number_sample.js
9007199254740991
9007199254740992 //+2したのに??
String型は文字列を扱う型です。
シングルクォート(')またはダブルクォート(")で囲んだ値を文字列として扱います。
let a = "hello"
let b: string = "my name is marsquai"
console.log(a + b);
$ tsc string_sample.ts
$ node string_sample.js
hellomy name is marsquai
またString型はリテラル型をサポートしているので特定の値のみに限定した宣言をすることも可能です。
let a: "hello" = "hello"
const b: string = "my name is marsquai"