投稿日:2020年11月11日
TypeScriptは静的型付け言語です。Javascriptの動的型付けとは挙動が異なっていて、その点に注意しないと思わぬバグを生んでしまいます。この記事ではTypeScriptにおける型システムについて解説しています。
この記事ではTypeScriptの型システムの基礎について解説しています。
TypeScriptの型指定には明示的な構文で指定する方法と、型を自動的に推論させる方法の2つの方法があります。
型を明示的に指定する場合、アノテーションという値: 型
の形式で記述を使用します。
let age: number = 26 // 数値
let username: string = "marsquai" // 文字列
let is_superuser: boolean = true // bool
let areaIdArray: number[] = [1,2,3,4,5] // 配列
let userIdArray: Array<number> = [1,2,3,4,5] // 配列
let userInfo: [string, number, number] = ["marsquai", 26, 171] // タプル
指定した型と異なる値を入れようとした場合、トランスパイル時にエラーが投げられます。
let age: number = "26" // 数値
let username: string = 111111111111 // 文字列
let is_superuser: boolean = 0 // bool
let areaIdArray: number[] = ["aaa","bbb"] // 配列
let userIdArray: Array<number> = 100 // 配列
let userInfo: [string, number, number] = [171, "200"] // タプル
$ tsc explicit.ts
explicit.ts:1:5 - error TS2322: Type 'string' is not assignable to type 'number'.
1 let age: number = "26" // 数値
~~~
explicit.ts:2:5 - error TS2322: Type 'number' is not assignable to type 'string'.
2 let username: string = 111111111111 // 文字列
[...]
Found 8 errors.
型を指定しなかった場合、型は自動的に推論されます。
let age: number = 26 // 数値
let username: string = "marsquai" // 文字列
let is_superuser: boolean = true // bool
let areaIdArray: number[] = [1,2,3,4,5] // 配列
let userIdArray: Array<number> = [1,2,3,4,5] // 配列
let userInfo: [string, number, number] = ["marsquai", 26, 171] // タプル
型を指定しなかった場合にも、内部的には型は存在しています。
変数宣言時に値を代入している場合、その値と違う型の値を入れようとするとエラーが投げられます。
let firstName = "marsquai"
firstName = 10
$ tsc implicit.ts
implicit.ts:2:1 - error TS2322: Type 'number' is not assignable to type 'string'.
2 firstName = 10
~~~~~~~~~
Found 1 error.
また、内部的に型が存在しているため、VSCodeなどのエディタのインテリセンスで、は、その型のメソッドなどを正しく表示してくれます。
(これは素晴らしい!!)
Javascriptの実行環境によってはその実行環境側で型を定義していたりします。
しかし、デフォルトの状態のTypeScriptはそれぞれの実行環境でどのような型が使えるのかを知る術がありません。
例えば、
nodejsにはBuffer型というものがあります。
TypeScriptをインストールしただけの環境で以下のようなコードを書いた場合、
let buffer: Buffer;
トランスパイルでエラーがなげられてしまいます。
$ tsc sample.ts
sample.ts:1:13 - error TS2580: Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i @types/node`.
1 let buffer: Buffer;
~~~~~~
Found 1 error.
この問題は型の宣言をインストールすることで解決できます。
開発している環境にnpmがインストールされている場合、ほぼすべての型はそれでインストールすることができます。型のパッケージの名前は@type/~~~のような形になっています。
今回のnodejsの場合パッケージ名は@types/nodeです(エラーメッセージにも書いてありますね!!)。
プロジェクトで使用するパッケージは、デプロイや複数人での共同作業を考えると、そのプロジェクトのディレクトリ内だけで依存関係を解決できることがのぞましいです。
npmのインストールのオプションに--save-devをつけることで作業ディレクトリのnode_modulesというディレクトリに依存関係を入れることができます。
$ npm init # プロジェクトの初期化
$ npm install --save-dev typescript @types/node
(一応TypeScriptも入れておきました!)
以下のようなBufferの定義がインストールされているはずです。
[...]
declare class Buffer extends Uint8Array {
/**
* Allocates a new buffer containing the given {str}.
*
* @param str String to store in buffer.
* @param encoding encoding to use, optional. Default is 'utf8'
* @deprecated since v10.0.0 - Use `Buffer.from(string[, encoding])` instead.
*/
constructor(str: string, encoding?: BufferEncoding);
/**
[...]
再度トランスパイルしてみましょう!
$ tsc sample.ts
問題なくコンパイルできました!