TypeScriptを基礎からやってみた

## はじめに
[ｋ．ｓ．ロジャース](https://www.wantedly.com/companies/ks-rogers)の藤本です。

今まで雰囲気でTypeScriptを書いていて正解がわからなくなることがあるため
改めて基礎から学びなおしてみました。自分の備忘録として残しておきます。

## 基本の型（プリミティブ型）

基本的に使うのはこの辺り？

- boolean
- number
- string

```typescript
// let 変数名:型 = 値;
let hoge:string = 'Hello World';
```

## リテラル型

指定した文字列のみ許可
かつ、文字列のリテラル型を持つ値はstringとして扱うことができる

```typescript
let hoge: 'message' = 'message';
let fuga: string = hoge;
```

以下のような場合は、エラーとなる

```typescript
let hoge: 'message' = 'Hello World';
// error TS2322: Type '"Hello World"' is not assignable to type '"message"'.
```

## union型

`|` を用いて記述することによりstring型、number型のどちらにも対応するような形で宣言することができる。

```typescript
let hoge:string | number;
hoge = 'Hello';
hoge = 222; // 数値を代入してもエラーにならない
```

以下のように使用も可能

```typescript
let message: 'Hello' | 'World';
message = 'Hello';
message = 'World';
message = '!!'; // Errro: 型 '"!!"' を型 '"Hello" | "World"' に割り当てることはできません。
```

## オブジェクト型

各プロパティに型指定ができる

```typescript
interface MyInterface {
    hoge: string;
    fuga: number;
}

const piyo: MyInterface = {
    hoge: 'message',
    fuga: 100
}
```

短ければそのまま書くこともできる

```typescript
const piyo: { hoge: string, fuga: number } = {
    hoge: 'message',
    fuga: 100
}
```

`?`を付けるとnullableとして宣言できる

```typescript
interface MyInterface {
    hoge: string;
    fuga?: number;
}

const piyo: MyInterface = {
    hoge: 'message'
}
```

`readonly`を付けると再代入ができなくなる。

```typescript
interface MyInterface {
    readonly hoge: string;
    fuga?: number;
}

const piyo: MyInterface = {
    hoge: 'message'
}

piyo.hoge = 'Hello';
// error TS2540: Cannot assign to 'hoge' because it is a read-only property.
```

## Class

```typescript
class Cat {
    constructor(name: string, age: number) {
        console.log(name, age);
    }
}

new Cat('Tama', 5);
```

ちなみにトランスパイル後はこうなっていました。

```javascript
var Cat = /** @class */ (function () {
    function Cat(name, age) {
        console.log(name, age);
    }
    return Cat;
}());
new Cat('Tama', 5);
```

## 外部Module

```typescript:util.ts
export const HOGE = "hoge";
const FUGA = "fuga";
```

```typescript:test.ts
import { HOGE } from "./util";
import { FUGA } from "./util";  // error
// エクスポートされたメンバー 'FUGA' がありません

console.log(HOGE);　// 'hoge'が出力される
```

## 内部Module

```typescript
namespace exampleA {
    export let hoge:string;
    let fuga:string;
}

namespace exampleB {
    export let hoge:string;
}

exampleA.hoge = "Hello";
exampleA.fuga = "Hello"; // 参照できないためerror
exampleB.hoge = "World";

console.log(exampleA.hoge);
console.log(exampleB.hoge);
```

## enum

```typescript
enum Fruit {
    apple = 10,
    grape = 20,
    lemon = 30
}

console.log(Fruit.apple, Fruit.grape, Fruit.lemon);
// 10 20 30が表示される
```

## Symbol

シンボルは不変で一意となる。

```typescript
let hoge = Symbol("key");
let fuga = Symbol("key");
console.log(hoge === fuga); // 結果: false
```

色んな面で便利に使えるとは思いますが
今回は簡単な例としてユニークのキーを作るのに使用します。

以下、非常に悪い例です。

```typescript
let key = 'key_' + Math.random();
hoge[key] = true;
```

こんな作り方はまずしないと思いますが・・・。
上記だと100%ユニークではないので、もっと正しく書くのであれば
keyの重複チェックが必要となり結果これよりは長くなります。

```typescript
let key = Symbol("key");
hoge[key] = true;
```

こう書けば確実にユニークになり、かつ可読性も良いので便利そう

## Generics

まずGenericsを使わない例として、以下のように
渡した文字をただ返すだけの関数の型を見てみます。

```typescript
const returnString = (x: string): string => x;
const returnNumber = (x: number): number => x;

console.log(typeof(returnString('10')));
console.log(typeof(returnNumber(10)));
// 結果: string number
```

内部処理は一緒なのに、型が違うだけで関数を二つ用意しなければいけません。
Genericsを利用すると以下のように書くことができます。

```typescript
const returnGenerics = <T>(x: T): T => x

console.log(typeof(returnGenerics<string>('10')));
console.log(typeof(returnGenerics<number>(10)));
console.log(typeof(returnGenerics<boolean>(false)));
// 結果: string number boolean
```
Classに使用することも可能です。

```typescript
class testGenerics<T> {
    private value: T;

    constructor(value:T) {
        this.value = value;
    }

    public getValue():T {
        return this.value;
    }
}

let outputString = new testGenerics<string>('hoge');
let outputNumber = new testGenerics<number>(10);
let outputBooleang = new testGenerics<boolean>(false);

console.log(outputString.getValue(), outputNumber.getValue(), outputBooleang.getValue());
// 結果: hoge 10 false

console.log(typeof(outputString.getValue()));
console.log(typeof(outputNumber.getValue()));
console.log(typeof(outputBooleang.getValue()));
// 結果: string number boolean
```

# 終わり
もっともっと基礎的な部分はあると思いますが
とりあえずはこんなところにしておきます。

「これは最初のうちに覚えたほうがいいよ！」
というのがあれば是非、ご教授頂けますとうれしいですmm

### Wantedlyでもブログ投稿してます
Techブログに加えて会社ブログなどもやっているので、気になった方はぜひ覗いてみてください。
https://www.wantedly.com/companies/ks-rogers