76
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【TypeScript】TypeScriptの雰囲気を掴もう

76
Last updated at Posted at 2019-03-12

はじめに

ざっくり静的型付け言語とES6よりも拡張されたクラスベースを理解することが目的。
TypeScriptを知らない人、静的型付け言語を使ったことがない人、Java等のオブジェクト指向言語を使ったことがない人向け。
自分自身も最近はじめたため誤りがあれば是非教えてくださいmm

TypeScriptの特徴

  • 静的な型システム
  • クラスベースのオブジェクト指向の拡張

参考

TypeScriptの実行

TypeScriptをインストール

.bash
npm install -g typescript

hello.tsを作成

.hello.ts
function greeter(person: string) {
    return "Hello, " + person;
}

geeter('taro')

コンパイル

.bash
tsc hello.ts

hello.jsがつくられる

hello.js
function greeter(person) {
    return "Hello, " + person;
}
greeter('taro');

コンパイルが失敗するようにhello.tsを修正

.hello.ts
function greeter(person: string) {
    return "Hello, " + person;
}

geeter(10)

エラーになる

.bash
hello.ts:5:9 - error TS2345: Argument of type '10' is not assignable to parameter of type 'string'.

5 greeter(10)
          ~~


Found 1 error.

データ型

基本

TypeScriptの静的型(Type)システムにおけるデータ型

  • number: 数値型
  • string: 文字列型
  • boolean: 真偽型
  • symbol: シンボル型
  • any: 任意の型
  • object型: 配列型、タプル型、クラス型、インターフェイス型、関数型
.ts
let data: string = 'hoge'
data = 'fuga'
data = 100 // エラー

型推論

型を省略するこも可能

変数宣言で型が省略された場合、初期値から型推論が行われる

.ts
let data = 100 // 初期値がnumberなので型はnumberだとみなされる
data = 200
data = 'hoge' // エラー

let data2 = 'hoge'
data2 = 'fuga'
data2 = 100 // エラー

let data3 // 初期値を省略すると型はanyとみなされる
data3 = 'fuga'
data3 = 100 //エラーにならない

let data4: any = 100
data4 = 150
data4 = 'hoge' // エラーにならない

let data5 = undefined // 初期値はundefined/nullを指定した場合もany型とみなされる
data5 = 100
data5 = 'hoge' // エラーにならない

型アサーション

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

.ts
function hello(name: string) {
    return `${name}さん、こんにちは!`
}

// 数値型を渡すとエラーになる
hello(100)

// any型に変換
hello(<any>100)

// as構文でも変換可能
hello(100 as any)

配列

.ts
// 基本
let data: string[] = ['apple', 'orange', 'peach']
console.log(data[0]) // apple

// ジェネリック記法
let data2: Array<string> = ['apple', 'oarange', 'peach']

連想配列

.ts
// indexの部分は何でも良い
let obj: { [index: string]: string } = {
    'apple': '青森',
    'orange': '愛媛',
    'peach': '群馬'
}
  • 連想配列の注意点

プロパティ名がStringの時に限りドット記法によるアクセスが可能だが、その場合は最初に定義しておく必要がある。

.ts
let obj = {
    'apple': '青森',
    'orange': '愛媛',
    'peach': '群馬'
}
obj.grape = '山梨' //エラー

// Property 'grape' does not exist on type '{ 'apple': string; 'orange': string; 'peach': string; }'.

obj['grape'] = '山梨' // ブラケット記法ならプロパティの追加が可能

列挙型

列挙型はユニークな値の有限集合。重複はエラーになる。

.ts
enum Fruit {
    Apple,
    Orange,
    Peach
}

let f: Fruit = Fruit.Apple
console.log(f) // 0
console.log(Fruit[f]) // Apple

タプル型

異なる型の集合

.ts
let data: [string, number, boolean] = [ 'hoge', 100, true]

型エイリアスをつくることが出来る

.ts
type SmapleType = [string, number, string]

let data: SampleType = ['hoge', 100, 'fuga']

ユニオン型

.ts
let data: string | boolean
data = 'hoge'
data = false
dat = 100 // エラー

let data2: (string | number)[] = ['hoge', 100, 100]

文字列リテラル型

.ts
type Fruit = 'apple' | 'orange' | 'peach'

let data: Fruit = 'apple'
data = 'grape' // エラー

関数

基本

.ts
function hello(name: string): string {
    return `${name}さん、こんにちは!`
}

hello('tom') //tomさん、こんにちは!

let hello2 = (name: string): string => {
    return `${name}さん、こんにちは!`
}

hello2('tom') //tomさん、こんにちは!

返り値がない場合はvoidを指定

.ts
function hello(name: string): void {
    console.log(name)
}

引数の省略

.ts
function hello(name?: string): string {
    return name === undefined ? 'スルー' : `${name}さん、こんにちは!`
}

hello() //スルー

引数のデフォルト値

.ts
function hello(name: string = 'tom'): string {
    return `${name}さん、こんにちは!`
}

hello() //tomさん、こんにちは!

可変長引数

.ts
function hello(...names: string[]) {
    let greet = 'こんにちは!'
    names.forEach(name => {
        greet = `${greet}${name}さん`
    })
    return greet
}

alert(hello('tom', 'risa')) //こんにちは!、tomさん、risaさん

オブジェクト指向構文

ES6によりクラスベースのオブジェクト指向が登場したが、TypeScriptはそれをさらに拡張する。
具体的には以下のような機能を提供する。

  • アクセス修飾子
  • インターフェイス
  • ジェネリック

基本的なクラス

.ts
class Person {
    name: string
    job: string

    constructor(name: string, job: string) {
        this.name = name
        this.job = job
    }

    introduce(): string {
        return `${this.name}${this.job}です`
    }
}

let tom = new Person('tom', 'エンジニア')
console.log(tom.introduce()) //tomはエンジニアです
let john = new Person('john', 10) // エラー

アクセス修飾子

  • public クラスの外からアクセス可能(デフォルト)
  • protected 同じクラス、またはその派生クラスからアクセス可能
  • private 同じクラスからのみアクセス可能
.ts
class Person {
    private name: string
    private job: string

    constructor(name: string, job: string) {
        this.name = name
        this.job = job
    }

    public introduce(): string {
        return `${this.name}${this.job}です`
    }
}

let tom = new Person('tom', 'エンジニア')
console.log(tom.introduce()) //tomはエンジニアです
console.log(tom.name) //エラー

//Property 'name' is private and only accessible within class 'Person'.

TypeScriptでは以下のようにコンストラクターを書くことも可能

.ts
class Person {
    constructor(private name: string, private job: string) {
        this.name = name
        this.job = job
    }

    public introduce(): string {
        return `${this.name}${this.job}です`
    }
}

getter / setter

.ts
class Person {
    private _age: number

    get age(): number {
        return this._age
    }

    set age(value: number) {
        if (value < 0) {
            throw new RangeError('ageプロパティは整数で指定してください')
        }
        this._age = value
    }
}
let p = new Person()
p.age = 10
console.log(p.age)

getterはプロパティの参照時に呼び出される
setterはプロパティの書き込み時に呼び出される

static修飾子

.ts
class Figure {
    public static Pi: number = 3.14

    public static circle(radius: number): number {
        // 静的メンバーにアクセスする時はthisを明示する
        return radius * radius * this.Pi
    }
}
console.log(Figure.Pi) //3.14
console.log(Figure.circle(2)) //12.56

名前空間

.ts
namespace MainApp {
    export class Hoge {
        //...
    }
}
namespace MainApp2 {
    export class Hoge {
        //...
    }
}
let app = new MainApp.Hoge()

namespaceは入れ子にすることもできる

継承

.ts
// 継承元のクラス(スーパークラス/親クラス/基底クラス)
class Person {
    protected name: string
    protected sex: string

    constructor(name: string, sex: string) {
        this.name = name
        this.sex = sex
    }

    show(): string {
        return `${this.name}${this.sex}です`
    }
}

// 継承して出来たクラス(サブクラス/小クラス/派生クラス)
class Engineer extends Person {
    work(): string {
        return `${this.name}はプログラミングします`
    }
}

let engineer = new Engineer('tom', '')
console.log(engineer.show()) //tomは男です
console.log(engineer.work()) //tomはプログラミングします

オーバーライド

.ts
class Person {
    protected name: string
    protected sex: string

    constructor(name: string, sex: string) {
        this.name = name
        this.sex = sex
    }

    show(): string {
        return `${this.name}${this.sex}です。`
    }
}

class Engineer extends Person {
    protected lang: string

    constructor(name: string, sex: string, lang: string) {
        super(name, sex)
        this.lang = lang
    }

    //showメソッドをオーバーライド
    show(): string {
        return super.show() + `好きな言語は${this.lang}です。`
    }
}

let engineer = new Engineer('tom', '', 'TypeScript')
console.log(engineer.show()) //tomは男です。好きな言語はTypeScriptです。

抽象メソッド

オーバーライドは派生クラスで基底クラスの上書きを強制しない
抽象メソッドは派生クラスで基底クラスの上書きを強制する

.ts
//抽象クラスを宣言
abstract class Figure {
    constructor(protected width: number, protected height: number) {}
    //abstract修飾子はコードブロックを持たず最後に「;」で区切る
    abstract getArea() :number;
}

class Triangle extends Figure {
    //抽象メソッドをオーバーライドが必須
    getArea(): number {
        return this.width * this.height / 2
    }
}

let triangle = new Triangle(10, 5)
console.log(triangle.getArea()) //25

インターフェイス

TypeScriptは一度に一つのクラスしか継承できない(単一継承)
インターフェイスは複数のインターフェイスを同時に継承できる(インターフェイスを継承することを実装すると言う)
インターフェイスは全てのメソッドが抽象メソッドである特別なクラス
派生クラスのことを実装クラスと言う

.ts
//インターフェイスを宣言
interface Figure {
    getArea(): number;
}

class Triangle implements Figure {
    constructor(private width: number, protected height: number) {}
    getArea() :number {
        return this.width * this.heigth / 2
    }
}

let triangle = new Triangle(100, 6)
console.log(t.getArea()) //300
  • インターフェイスの制限
  • メソッドは全て抽象メソッド。抽象メソッドであることは自明なのでabstract修飾子は指定しない
  • 全てのメンバーはpublicであることが自明なのでアクセス修飾子は指定しない
  • staticメンバーも宣言できない
  • インターフェイスを継承してインターフェイスを宣言する

インターフェイスの継承にはimplementsではなくextendsを使う

.ts
interface Hoge extends Foo, Bar {}

ジェネリック

汎用的なクラス、メソッドに対して特定の型を紐付けるための機能

.ts
class MyGenerics<Ge> {
    value: Ge
    getValue(): Ge {
        return this.value
    }
}
let ge = new MyGenerics<string>()
ge.value = 'generic'
console.log(ge.getValue) //generic
76
76
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?