はじめに
現在担当するプロジェクトでTypeScriptが使われていたので学習備忘録です。
- TypeScriptってよく聞くけどイマイチよく分からない
- 導入することで何が嬉しいの?
そんな疑問を解決したい。
TypeScriptシリーズ全4回連載中です
知識ゼロから始めるTypeScript 〜基本編〜 今ココ
知識ゼロから始めるTypeScript 〜関数編〜
[知識ゼロから始めるTypeScript 〜クラス編〜]
(https://qiita.com/yukiji/items/3db06601ece7f080b0d0)
[知識ゼロから始めるTypeScript 〜応用編〜]
(https://qiita.com/yukiji/items/e890053e62d2f7edc7c7)
TypeScriptとは
- Javascriptに静的型付けの定義をすることで堅牢なプログラムを書くことが可能。
- 型を定義することによりプログラムを動かす前にエラーに気付くことが出来る。
- 型を定義することによりプログラムを動かす前に意図しない型が代入されるのを防ぐ。
TypeScriptを導入する目的
- 型安全を確保してバグを減らすのが目的
実行環境
- MacOS Catalina 10.15.2
- VScode
使用するモジュールのインストール
$ npm i -D typescript ts-node ts-node-dev
typescript
typescript本体
ts-node
.tsファイルをコンパイルして実行する
ts-node-dev
ts-nodeに依存している
実行したts-nodeをwatchしてくれる。
package.jsonを編集
- 手軽に実行できるように
scripts
を登録しておく
"scripts": {
"dev": "ts-node-dev --respawn"
}
tsconfig.jsonを作成
$ npx tsc --init
tsconfig.json
が生成される
細かな設定ができるが、今回はデフォルトの設定でOK
実行サンプル
export {}
let moji: string = "ハロー世界"
console.log(moji)
export{}
=モジュール化
するという意味。
モジュール化することにより、変数のスコープがグローバルになることを防ぐ。
上記の例は変数moji
にstring型
の型宣言をしている
この場合、文字列(string型)しか受け付けず、string型以外はコンパイルエラーになる。
基本的には変数名: 型
の様な書き方をする
実行してみる
$ npm run dev sample.ts
// ハロー世界
tsファイルの内容をJavaScriptにコンパイルして実行してくれる
一度実行するとファイルはウォッチされるので、ファイルを保存するたびに実行されるので便利
型一覧
number型、string型
let year: number = 1969
let name: string = 'foo'
boolean型
let isFinished: boolean = true
array型
let numbers: number[] = [1, 2, 3]
//非推奨の書き方
let strings2: Array<string> = ['Tokyo', 'Nagoya']
//二次元配列の場合
let nijigenHairetsu: number[][] = [
[50, 100],
[150, 300]
]
//型が混在する場合
let hairetsu: (string | number | boolean)[] = [1, false, 'Japan']
tuple型
- 配列の中身の0番目がstring型、2番目がnumber型などにしたい場合に使う
let profile: [string, number] = ['foo', 1969]
any型
- あまり望ましくない形 (型推論ギブアップ宣言)
- APIなどでデータが返ってくる場合、そのデータの構造の予測はできないので、エンジニアが指定する必要がある。
import axios from 'axios'
let url: string = 'https://xxx'
axios.get(url).then(function(response) {
let data: any
// any型=どんな構造のオブジェクトが返ってくるか分からない
data = response.data
})
interface型
- オブジェクトの型を作ることが出来る
interface ObjectInterface {
name: string
age: number
}
let object: ObjectInterface = {
name: 'foo',
age: 26
}
先ほどのany型
のAPIから返されるオブジェクトの構造がわかるときに使用してみる
import axios from 'axios'
export {}
let url: string = 'https://xxx'
axios.get(url).then(function(response) {
interface Article {
id: number
title: string
description: string
}
// APIから返されるデータ構造を指定
let data: Article[]
data = response.data
})
void型
- 関数からの戻り値がないことを期待するような型
- 関数には必ずしも
return
があるわけでは無い。
function returnNoting(): void {
console.log('I dont return anything')
}
console.log(returnNoting())
null型、undefined型
- そのまんま
let absence: null = null
let data: undefined = undefined
never型
- 例外を起こす関数や呼び元に戻ってこない関数の戻り値に対応する型
function error(message: string): never {
throw new Error(message)
}
object型
- オブジェクトの構造がわかっている場合は、各種プロパティに対しても型宣言する。
let profile2: { name: string, age: number } = { name: 'foo', age: 26 }
型エイリアス(Type Aliases)
- 一度作成した型を流用できる。
type Mojiretsu = string
const fooString: string = 'Hello'
const fooString2: Mojiretsu = 'Hello'
const example1 = {
name: 'foo',
age: 26
}
type Profile = {
name: string,
age: number
}
const example2: Profile = {
name: 'buzz',
age: 27
}
// example1のデータ構造を設定できる
type Profile2 = typeof example1
unknown型
- ざっくり言うと型安全なany型
- any型を積極的に使っているとコンパイルエラーにはならないものの、実行時にエラーになってしまう。
- 一旦フワッと型定義したいときにany型に依存するのではなく暫定的にunknown型を定義する
- typeofを使ってある特定の型であることを確認しながら安全にコードを実行させる仕組みのことをタイプガードという
const kansu = (): number => 26
let numberUnknown: unknown = kansu()
// typeofを使って型を絞る
if (typeof numberUnknown === 'number') {
let sumUnknown = numberUnknown + 10
}
intersection型
- 既存の型を再利用して新たな型を作る
type Picher1 = {
throwingSpeed: number
}
type Batter1 = {
battingAverage: number
}
const Daimaou: Picher1 = {
throwingSpeed: 154
}
const Ochiai: Batter1 = {
battingAverage: 0.367
}
type TwoWayPlayer = Picher1 & Batter1
const Tsuneta: TwoWayPlayer = {
throwingSpeed: 154,
battingAverage: 0.367
}
union型
- 型のor的な感じ
- 下の例だと
number型
かstring型
のどちらも対応した型宣言ができる
let value: number | string = 1
value = 'foo'
value = 100
Literal型
- 変数に代入されるパターンを設定したい時
- 例えばstring型でも「この文字列しか受け付けない」様なパターンを作れる
let dayOfTheWeek: '日'|'月'|'火'|'水'|'木'|'金'|'土' = '日'
dayOfTheWeek = '月'
let month: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 = 1
month = 12
enum型
- 数値や文字列を列挙するときに便利
- 自動的に番号を付与してくれる
- 数値は設定できる(初期値は0)
enum Months {
//初期値は0なので1を設定
January = 1,
February,
March,
}
console.log(Months.January)
// 1
enum COLORS {
RED = '#FF0000',
BLUE = '#0000FF'
}
let green = COLORS.GREEN
// 追加も可能
補足
ワークスペースのtypescriptを使用する
VScodeにはデフォルトでTypeScript
がインストールされている。
しかし、基本的にはプロジェクト毎に管理したいのでpackage.json
でインストールしたTypeScriptを使いたい。
①VScode右下のステータスバーTypeScript
横の数字(画像では3.8.3)
をクリックする
②ワークスペースのバージョンを使用
をクリック
これで完了。
大事な設定なのでしっかり行いたい。
ts-nodeでエラーが出たとき
- パッケージのバージョン履歴を調べて一つずつ試していく。
- エラーが出ないバージョンをインストールして対処
$ npm info ts-node versions
npm uninstall -D ts-node
npm uninstall -D ts-node@x.x.x
まとめ
型宣言は変数に対して制約が強くなるような型を定義することが理想的。
型安全なコードを書いて堅牢なプログラムを書いていきたい