📝

TypeScriptの基礎をシンプルに紹介する

2022/04/24に公開

はじめに

「JavaScriptは理解してるけどTypeScriptはそんなに」という方が対象です。
ES2015のJavaScriptに含まれる or 複雑な項目に関しては除外します。

TypeScriptとは

JavaScriptに型システムを備えた拡張言語。
JavaScriptのコードはほとんどそのまま動作する。

データ型

プリミティブ型

数値型(number)…1,2,3
文字列型(string)…'hoge', 'fuga'
真偽型(boolean)…true, false
シンボル型(symbol)…値が同一、かつ初期化の場所も同じ

オブジェクト型

配列型、タプル型、クラス型、インターフェイス型、関数型...etc
→ 後述する

型なし

any…任意の型

変数宣言

変数名の横に「:型」という形式で設定する。

let name:string = 'hoge'
let age:number = 100 
let flg:boolean = true 

型推論

変数宣言で型が省略された場合は、初期値から型を類推する。

let data = 100
data = 200
data = 'hoge' // NG

型アサーション

互換性のある型であれば、型を明示的に変換できる。

let age:string = <string>30
let age:string = 30 as string

配列

配列型

以下の例では、numberが要素のデータ型

let arrayData:number[] = [1,2,3,4,5]
let arrayData:number[][] = [[1,2],[3,4]] // 多次元配列

連想配列型

以下の例では、numberがインデックスのデータ型、stringが値のデータ型

let objData:{[index:number]:string} = {
 1:'ほげ',
 2:'ふー',
 3:'ばー'
}

タプル型

複数の型が混在した配列

let tuple: [string, number, boolean] = ['dog', 100, true]

列挙型

列挙型は関連する定数を束ねる役割を担う。
以下の例では、MALEなどの各項目が「列挙子」となる。
列挙子に値を割り当てない場合、デフォルトで0から順に数値が割り振られる。

enum Animal {
 DOG = 1,
 CAT = 5,
 MONKEY = 10
}

関数

関数型では引数と戻り値の型を定義できる。

void

値がないことを意味する型

function hoge (name:string): void {
 console.log('hoge')
}

never

終点まで辿り着かないことを意味する型 → 例外スロー、無限ループ等

function huga (name:string): never {
 while (true) {
  console.log('huga')
 }
}

オーバーロード

同じ名前だが引数や戻り値が異なる関数を定義すること
以下の例では、引数の型としてstringとnumberが許容される。

// 引数の型が異なる
function hoge (value:string):void
function hoge (value:number):void

function hoge (value:any):void {
 // 型ガード(変数の型を特定)して処理を実行
 if (typeof value === 'string') {
  // 引数がstringの時の処理
 } else{
  // 引数がnumberの時の処理
 }
}

共用型(ユニオン型)

複数の型の中のどれかを表す型

let data: string | number

リテラル型

リテラルがそのまま型として使用される。
以下の例では、'march'や'april'などを共用型で連結し、
型エイリアスでspringという別名を付与している。

type spring = 'march' | 'april' | 'may'
type dice = 1 | 2 | 3 | 4 | 5 | 6

型エイリアス

特定の型に別名を設定する仕組み

type hogeType = [string, number, boolean]
let data:hogeType = ['aaa', 'bbb', 100, true]

クラス

ES2015以降使えるクラスと機能は似ているが、
TypeScriptにだけ備わっている機能を紹介する。

型アノテーション

プロパティやメソッド内の引数・戻り値などで型を使用できる。

アクセス修飾子

プロパティ/メソッドにアクセスの可否レベルを設定できる。
public…クラスの外からアクセス可能
protected…同じクラスか継承されたクラスからアクセス可能
private…クラス内からアクセス可能

readonly

フィールドを読み取り専用にする

class Person {
  private name:string
  protected age:number
  constructor (name:string, age:number) {
    this.name = name
    this.age = age
  }
  public hoge():string {
    return`${this.name}${this.age}歳です。`
  }
}

インターフェイス

全てのメソッドが抽象メソッドである特別なクラス。
全てのメソッドが抽象メソッドなので、abstract修飾子は指定できない。
全てのメンバーがpublicなので、アクセス修飾子は指定できない。
staticメンバーも宣言できない。

interface Hoge {
  foo(): number
}

継承

クラスは単一継承しかできないが、インターフェイスは複数継承が可能。
インターフェイスを継承して、新たなインターフェイスを宣言できる。

interface Hoge extends aaa, bbb {
  foo(): number
}

クラスを継承して、インターフェイスを宣言することもできる。
その場合、クラスの実装は無視されてシグニチャだけが継承される。

class HogeClass {
  aaa () {...}
}
interface Hoge extends HogeClass {
  aaa () {...}
}

型注釈として使う

オブジェクト、関数、メソッドなどで使用できる。

// オブジェクト
interface ccc {
  name?: string; // 省略可能
  readonly age: number
}
let person:ccc = {
  name: 'Mike'
}

// 関数
interface ddd {
  (a: string, b:number): string
}
let plus: ddd = function (x:string,y:number):string {
  return x + y // 仮引数の名前は異なっても問題ない
}

おわりに

基本的な項目に絞って紹介しました。
本記事で触れなかった部分として、構造的部分型という概念があります。
これはとても重要なので説明ページのリンクを貼っておきます。
サバイバルTypeScript

Discussion