TypeScriptのまとめ

言語
スポンサーリンク

言語ごとに書き方が若干異なる部分を中心にまとめています。

基本的にTypeScriptはJavaScriptに似ているので、本ページではJavaScriptと違う部分を中心に記載します。
JavaScriptのまとめは以下を参照。

http://aegisfleet.wp.xdomain.jp/javascript%e3%81%ae%e3%81%be%e3%81%a8%e3%82%81/

特徴

TypeScriptは、Microsoftによって開発されたプログラミング言語です。その特徴は以下の通りです。

  • JavaScriptに型定義を追加した言語
  • 型定義により型のチェックを行うことで、バグを早期に発見できる
  • オブジェクト指向や関数型プログラミングにも対応していること
  • JavaScriptのスーパーセットであるため、JavaScriptコードをそのまま使用することができる
  • 企業での利用が増えており、最近ではAngularなどのフレームワークでも採用されている

TypeScriptはJavaScriptに型定義を追加した言語であり、型定義により型のチェックを行うことで、バグを早期に発見できるという特長があります。
また、オブジェクト指向や関数型プログラミングにも対応しているため、より柔軟なプログラミングが可能です。
TypeScriptはJavaScriptのスーパーセットであるため、JavaScriptコードをそのまま使用することができます。
最近では、企業での利用が増えており、Angularなどのフレームワークでも採用されています。

お試し実行環境

TS Playground - An online editor for exploring TypeScript and JavaScript
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
ブラウザでプログラミング・実行ができる「オンライン実行環境」| paiza.IO
paiza.IOはオンラインですぐにプログラミングが始められる、オンライン実行環境です。Java,Ruby,Python,PHP,Perlなど主要32言語に対応。プログラミング学習にも。

※paizaの方は「fetch」が実行できないので注意。

参考サイト

TypeScript | TypeScript入門『サバイバルTypeScript』
TypeScript入門『サバイバルTypeScript』〜実務で使うなら最低限ここだけはおさえておきたいこと〜

変数宣言

TypeScriptの型宣言・全15実例
さてさて、前回記事「Laravel MixでTypeScriptを使う」では、いま巷で評判がいいTypeScriptをLaravel内で使う方法をご紹介しました。 TypeScriptはビルド作業が必要になるのがネックですが、次のJavaS...
TypeScriptの型入門 - Qiita
TypeScriptは型がついたJavaScriptです。プログラミングにおいて型があることの恩恵は大きく、近頃AltJSの代表格として人気を集めています。TypeScriptはもともと型のないJa…

プリミティブ型

俗に言う一般的(基本的)な型定義。JavaScriptを踏襲している。

説明
string 文字型
number 数値型
boolean 論理型
symbol シンボル型
bigint 長整数型(整数型との演算は不可)
null null型
undefined 未代入
let hoge: string = "hoge"
let fuga: number = 100
let piyo: boolean = false
let _null: null = null
let _undefined: undefined = undefined
console.log("hoge:", typeof hoge, hoge)
console.log("fuga:", typeof fuga, fuga)
console.log("piyo:", typeof piyo, piyo)
console.log("_null:", typeof _null, _null)  // nullはtypeofしたときobject型になる
console.log("_undefined:", typeof _undefined, _undefined)

変数における合併型(union)

複数の型が代入される可能性がある場合、「|(パイプライン)」を用いて宣言する。

let hoge: string | number  // stringとnumberのどちらかが代入される変数として宣言する

hoge = "hoge"  // 文字列を代入したので型がstringになる
console.log("hoge:", typeof hoge, hoge)

hoge = 100  // 数値を代入したので型がnumberになる
console.log("hoge:", typeof hoge, hoge)

unknown型

any型に近いが、一度値が代入されるとそこから変更できない型。

let hoge: unknown
console.log("hoge:", typeof hoge, hoge)
hoge = 100  // 数値を代入したので型がnumberになる
console.log("hoge:", typeof hoge, hoge)

if (typeof hoge === 'number') {
    console.log("hoge:", typeof hoge, hoge + 10)
}

配列の型定義

型の右隣に「[](ブラケット)」を記載する。

const hoge: string[] = ['a', 'b', 'c']
hoge.push('d')
const fuga: Array<number> = [1, 2, 3]
fuga.push(4)
const piyo: (string | number)[] = ['ABC', 123]  // 「|」を使って複数の型が使えるようにすることもできる
piyo.push('EFG')
piyo.push(456)
console.log(hoge, fuga, piyo)

読み取り専用の配列

「readonly」を付与することで読み取り専用にできる。

const hoge: readonly string[] = ['a', 'b', 'c']
//hoge.push('d') // readonlyにより追加ができなくなる

const fuga: ReadonlyArray<number> = [1, 2, 3]
//fuga.push(4) // ReadonlyArrayにより追加ができなくなる

const piyo: Readonly<number[]> = [1, 2, 3]
//piyo.push(4) // Readonlyにより追加ができなくなる

console.log(hoge, fuga, piyo)

タプルとタプルの可変長型定義

// タプル
let hoge: [number, string] = [200, 'OK']  // 数値と文字列の配列
hoge = [400, 'NG']
console.log(hoge)

// タプルを使った可変長の型定義
const fuga: [number, ...string[]] = [1, '2', '3']  // 数値と複数の文字列の配列
fuga.push('4', '5')
console.log(fuga)

オブジェクトの型定義

オブジェクト内の各プロパティ(要素)に対して型を定義していく。

let obj: {
    key1: string
    key2: number
} = {
    key1: "hoge",
    key2: 100
}
console.log(obj)
console.log(obj.key1, obj.key2)

obj = {
    key1: "fuga",
    key2: 200
}

console.log(obj)
console.log(obj['key1'], obj['key2'])  // []の中に名前を文字列で入れても参照できる

オプショナルと読み取り専用

「?」を付ければオプショナルになり、「readonly」を付ければ読み取り専用になる。
オプショナルなキーに対して初期値を与えなかった場合は「undefined」となる。

let obj: {
    key1?: string
    readonly key2: number
} = {
    key2: 100
}
console.log(obj)
console.log(obj.key1)  // undefinedになる

obj.key1 = "fuga"
//obj.key2 = 200  // readonlyなので代入不可

console.log(obj)

obj = {  // オブジェクトごと再代入された場合は値が上書きされる
    key1: "piyo",
    key2: 300
}

console.log(obj)

可変長のプロパティを持つオブジェクト(インデックスシグネチャ)

プロパティを後から追加可能なオブジェクトが作れる。

const objects: {
    [key: string]: string  // キーに対して文字列を持つプロパティとして定義
} = {
    hoge: "HOGE",
    fuga: "FUGA"
}

objects.piyo = "PIYO"  // piyoというプロパティを追加

console.log(objects)

変数の型宣言(型エイリアス)

オブジェクトを宣言する際に型を指定するのではなく、予め「type」で宣言した型をオブジェクトに適用するやり方。

type Type = {
    hoge: string
    fuga: string
    piyo: number
}

const obj: Type = {  // 予め宣言していた型を使用する
    hoge: "HOGE",
    fuga: "FUGA",
    piyo: 100
}

console.log(obj)

オブジェクトにおける合併型(union)と交差型(intersection)

オブジェクトにおいても複数の型を定義可能となっている。その際、複数の型のプロパティを内包した交差型も使用できる。

type Type1 = {
    hoge: string
    fuga: string
}

type Type2 = {
    hoge: string
    piyo: number
}

type Type3 = Type1 | Type2  // 合併型(union)、Type1とType2のどちらかの型を使いたい場合の宣言方法
type Type4 = Type1 & Type2  // 交差型(intersection)、Type1とType2双方のプロパティを持つ型として宣言する

const obj1: Type3 = {
    hoge: "HOGE",
    fuga: "FUGA",
}

const obj2: Type3 = {
    hoge: "HOGE",
    fuga: "FUGA",
    piyo: 100        // Type1として定義するのであればType2のプロパティを定義するのはおかしいが、仕様としては定義可能
}

const obj3: Type4 = {
    hoge: "HOGE",
    fuga: "FUGA",
    piyo: 100
}

console.log(obj1)
console.log(obj2)
console.log(obj3)

関数宣言

void型

return文を持たない関数(戻り値が無い関数)。

never型

戻り値が返ってくることが決して無い関数(必ず例外発生する関数など)。

オプショナル引数とデフォルト引数

「?」を使うことで引数指定しなくても良い引数を作ることができる。
この際、何も引数を与えなかった場合は「undefined」となる。

また、引数にデフォルト値を与えることも出来るが、その際は「?」を付けては行けない。

// 第2引数は無くても動作する
const logMessage1 = (message1: string, message2?: string): void => {
    console.log(message1, message2)
}

// 第1引数、第2引数ともに無くても動作する
const logMessage2 = (message1: string = "Hello", message2: string = "world"): void => {
    console.log(message1, message2)
}

logMessage1("hoge")
logMessage1("hoge", "fuga")

logMessage2()
logMessage2("hoge")
logMessage2("hoge", "fuga")

残余引数(レスト引数)

可変長引数を扱う上で型定義を行う方法が「…(3点リーダー)」を付与するというもの。

// 引数がいくら増えても動作する
const logMessage = (...messages: string[]): void => {
   const message: string = messages.reduce((prevMessage, message) => {
      return prevMessage + " " + message
   }, "")
   console.log(message)
}

logMessage()
logMessage("hoge")
logMessage("hoge", "fuga")
logMessage("hoge", "fuga", "piyo")

関数の型宣言(呼び出しシグネチャ)

関数を宣言する際に引数や戻り値に対してその場で型を指定するのではなく、予め「type」で宣言した型を関数に適用するやり方。

// 呼び出しシグネチャ
type LogMessage1 = {
    (message: string): void
}

// 省略記法
type LogMessage2 = (message: string) => void

const logMessage1: LogMessage1 = (message) => {
    console.log(message)
}

const logMessage2: LogMessage2 = (message) => {
    console.log(message)
}

logMessage1("Hello world")
logMessage2("Hello world")

ジェネリック型

型の定義を「T」などで記載し、引数として受け取って型宣言を行うやり方。

type Type<T> = {
    (fuga: T, piyo: T): T  // 同じ型の2つの引数と同じ型の戻り値を持つ型
}
/*
一般的に「T,U,V,W」を用いるが、別に「A」でも「B」でも何でも良い
*/

const hoge: Type<string> = (fuga, piyo) => {  // 引数をstringでバインド
    return fuga + piyo
}
console.log(hoge("FUGA", "PIYO"))

const hogehoge: Type<number> = (fuga, piyo) => {  // 引数をnumberでバインド
    return fuga + piyo
}
console.log(hogehoge(10, 20))

複数の型を引数に与えることもできるし、省略記法も使用できる。

// 省略記法も使える
type Type<T, U> = (piyo: T) => U

// numberをstringに変換する関数
const hoge: Type<number, string> = (piyo) => {
    return piyo.toString()
}
console.log(hoge(100))

// stringをnumberに変換する関数
const fuga: Type<string, number> = (piyo) => {
    return parseInt(piyo)
}
console.log(fuga("100"))

クラス宣言

「constructor」内で宣言した変数はクラスの内のグローバル変数として参照できる。

class Hoge {
    constructor(
        private hoge: string,
        protected fuga: string,
        public piyo:string
    ) {}

    // privateで宣言されたhogeを更新するためのセッター
    setHoge(hoge: string) {
        this.hoge = hoge
    }
}

let hoge = new Hoge("HOGE", "FUGA", "PIYO")
//hoge.hoge = "HOGEHOGE" // privateなので代入できない
//hoge.fuga = "FUGAFUGA" // protectedなので代入できない
hoge.piyo = "PIYOPIYO"
hoge.setHoge("HOGEHOGE") // セッター経由でhogeを更新する
console.log(hoge)

継承と抽象クラス

「extends」で継承できるし、「abstract」で宣言すれば抽象クラスも作れる。

abstract class Fuga {
    // protectedで宣言することでサブクラスで操作可能とする
    protected fuga

    // fugaのセッターをサブクラスで実装させる
    abstract setFuga(fuga: string)
}

class Piyo extends Fuga {
    // 親クラスのメソッドをサブクラスで実装する
    setFuga(fuga: string) {
        this.fuga = fuga
    }
}

let piyo = new Piyo()
piyo.setFuga("FUGAFUGA")
console.log(piyo)

interfaceを用いた型宣言

「interface」は多重定義ができ、その場合は双方のプロパティを内包した交差型となる。

interface Hoge {
    hoge: string
}

// 同名のインタフェースを宣言
interface Hoge {
    fuga: string
}

// 同名のインタフェースが宣言された場合、両方のプロパティを内包する必要がある(typeで宣言した場合の交差型に相当する)
const hoge: Hoge = {
    hoge: "HOGE",
    fuga: "FUGA"
}

console.log(hoge)

// インタフェースを継承して、プロパティを追加
interface Fuga extends Hoge {
    piyo: string
}

// 親インタフェースのプロパティも含めて宣言する必要がある
const fuga: Fuga = {
    hoge: "HOGEHOGE",
    fuga: "FUGAFUGA",
    piyo: "PIYOPIYO"
}

console.log(fuga)

interfaceの実装方法

「implements」を用いてinterfaceで定義したものを実装することができる。

interface Hoge {
    hoge: string
}

class Hoge implements Hoge {
    // インタフェースで実装した変数を更新するメソッド
    setHoge(hoge: string) {
        this.hoge = hoge
    }
}

const hoge = new Hoge()
hoge.setHoge("HOGE")

console.log(hoge)

キャスト

.toString()やparseInt()も使えるが、型指定でキャストすることもできる。

const str: string = "100"
const num: number = 200

// 数値にキャスト
console.log(Number(str) + 200)
// 文字列にキャスト
console.log(String(num) + 300)

非同期処理を待ち合わせる(同期処理にする)方法

「Promise」を使用することで実行後の結果を「resolve」で受け渡しできる。

const fetchTenki = () => {
    return new Promise((resolve, reject) => {
        // ここから非同期処理
        return fetch("https://www.jma.go.jp/bosai/forecast/data/forecast/130000.json")
            .then((res) => {
                // ここも非同期処理
                res.json()
                    .then((json) => {
                       console.log("fetch json")
                       resolve(json)  // 正常時に(resolveで)取得したJSONを返却する
                    })
                    .catch((error) => {
                        console.error(error)
                        reject(null)  // 異常時は(reject)でnullを返却する
                    })
                })
            .catch((error) => {
               console.error(error)
               reject(null)
            })
    })
}

fetchTenki()
    .then((tenki) => {
        console.log(tenki)
    })

上記を別の書き方で表記する方法として、「async」と「await」を用いて書くことができる。

// asyncを宣言する、この際型は自動的にPromiseになる
const fetchTenki = async() => {
    // asyncが宣言されているのでawaitを使用することができる
    const res =  await fetch("https://www.jma.go.jp/bosai/forecast/data/forecast/130000.json")
        .then((res) => res)
        .catch((error) => {
            console.error(error)
            return null
        })

    if (!res) {
        return null
    }

    // ここも非同期処理なのでawaitを使用する
    const json = await res.json()
        .then((json) => json)
        .catch((error) => {
            console.error(error)
            return null
        })

    console.log("return json")
    return json
}

fetchTenki()
    .then((json) => {
        console.log(json)
    })

 

タイトルとURLをコピーしました