TypeScript基礎まとめ

##TypeScriptとは
TypeScriptとは、型のあるjavascript。
本来実行するまでエラーがでないjavascriptだが、TypeScriptを用いると、実行する前にエラーが出るようになる。
これにより安全かつ効率的にjavascriptのコードを書くことができる。
以下typescriptはtsと略します。

##型推論と明示的（型アノテーション）型宣言
####型推論
言葉の通りtsは方を推論する。
具体的には、

```
  const name = "sakai"
```
このようなコードをstrig型であると自動的に判断する。

####明示的型宣言（型アノテーション）
>アノテーションとは、「注釈」という意味の英単語で、ITの分野ではデータやプログラムの中に特殊な記法を用いて埋め込まれた付加情報のことをこのように呼ぶことが多い。

文字通り、明示的に方を宣言すること。
具体的には以下のように記述する。

```
　  const 変数名：　型の種類　= "内容" 
　  const name: string = "sakai"
```
変数になんの値が入ってくるかがわからない、明示的ではない時はこのように型アノテーション（明示的型宣言）を使用することで、コードを視覚的によりわかりやすくすることができる。

* 関数の引数に型をつける
* オブジェクトのプロパティに型をつける

みたいな時は型アノテーションを使用する。

##プリミティブ型
タイプスクリプトにおいて、一番の基本になる型。
>プログラミングの分野では、プログラミング言語の仕様としてあらかじめ用意されている最も基本的なデータ型のことを「プリミティブ型」（primitive data types）という。 「組み込みデータ型」「基本データ型」などと呼ばれることもある

主なプリミティブデータ（基本データ型）は、string、number、booleanの３つ。

* string →　全ての文字列を扱う型

```
  const name: string = "sakai";
```
* number →　整数、浮動小数点数、整数、負数、無限大、NaN(非数) 等、全ての数値を扱う型

```
  const age: number = 18;
```
* boolean → trueとfalseの2つの方を扱う型

```
  const isOver20: boolean = false;

  //判定式の結果も代入することができる。
  age: number = 18;
  const isOver20: boolean = age >= 20;
```

##リテラル型
> リテラルとは、コンピュータプログラムのソースコードなどの中に、特定のデータ型の値を直に記載したもの。また、そのように値をコードに書き入れるために定められている書式。

プリミティブ型を細分化したものとして、リテラル型という型がある。
リテラル型には、文字列のリテラル型、数値のリテラル型、真偽値のリテラル型がある。

####文字列のリテラル型

```
  const word: 'hoge' = 'hoge';
  const word: 'hoge' = 'foo'; 　//エラー
```
これは、'hoge'という文字列しか許容しない型となる。

注意するべき点として、文字列のリテラル型は、stringの部分型なので、string型としても扱うことができる。

```
  const word: 'hoge' = 'hoge';
  const test: string = word;
```

##リテラル型と型推論

上の例では明示的に方を宣言していたが、これを省略してもちゃんと推論される。

```
  const a = 'hoge';
  const b: 'bar' = a; //エラー
```

これは、hogeという値が、'hoge'型であると推論されることによる。

ただしこれは、constを用いて宣言した場合のこと。
letやvarと違い、constは内容が変わることがないことが約束されるので、変数の型を'hoge'とすることができる。
letやvarを使って変数を定義する場合は、最初に'hoge'が入っていたからといって、変数の型を明示的に'hoge'としてしまっては、値を変更することができなくなってしまい、不便になる。
そこで、letやvarで変数が定義される場合、推論される型は、リテラル型ではなく、対応するプリミティブ型全体に広げられる。

```
  let a = 'hoge' //aはstring型に推論される
  const b: string = a;
  const c: 'hoge' = a; //エラー
```

letやvarで定義した変数は、リテラル型ではなく、プリミティブ型に推論されるので、
上記の例であれば、'hoge'はstring型であると推論される。
その為、'hoge'というリテラル型を持つ変数に値を代入しようとした場合にはエラーが出る。

##オブジェクト型
jsの基本的な概念としてオブジェクトがあるが、tsにもオブジェクトを表現するための型がある。
tsではinterfaceという構文を用いることで、オブジェクト型に名前をつけることができる。
以下の例では、{foo: string;, bar: number}という型にObjという名前がつけられている。

```
  interface Obj {
    foo: string;
    bar: number;
  }

  const a: Obj = {
    foo: 'foo',
    bar: 3,    
  }
  
  //barプロパティの型が違う為エラー
  const b: Obj = {
    foo: 'foo',
    bar: 'bababa',
  };

  //barプロパティが存在しないためエラー
  const c: Obj = {
    foo: 'foo',
  }
```

jsではオブジェクトを自由に書き換えることができる。
プロパティを自由に書き換えたり、プロパティを付け加えたり、消したりすることも可能。
しかしtsでは、そのような操作は型によって制限される。
そうでなければ型を導入した意味がない。

一方tsでは構造的部分型を導入しているため、次のようなことが可能になる。

```
  interface Obj {
    foo: string;
    bar: number:
  }

  interface Obj2 {
    foo: string;
  }

  const a: Obj = {foo: 'foo', bar: 3};
  const b: Obj2 = a;
```

Objの方がプロパティが多いのに、なんでそれがObjに入るのか。
これを最初見たときはそう思ったが、よくよく考えてみると、オブジェクトというのは、結論、何も入っていないオブジェクトが一番広いということになる。

なぜなら、値の入っていないオブジェクトというのは、制約がないからだ。
よって、どんな値でも入れられることができる。

対して、値の入っているオブジェクトには、制約がある。
「string型の値と、number型を入れてくださいね」というオブジェクト型があるならば、そこにはstring型の値だけが入ったオブジェクトを入れることはできない。なぜならnumber型がないからだ。

このような理由から、プロパティが一つしかないObj2にプロパティの多いObjが入るということになる。

####オブジェクトリテラルについて

オブジェクト型に関しては、プロパティの少ないオブジェクトでも、条件を満たしてさえいればそこにプロパティの多いオブジェクトが入るという考え方であったが、オブジェクトリテラルになると、全く逆の結果になる。
同じようなことをしようとした場合に余計なプロパティが弾かれて、値を代入することができず、エラーになる。

```
  interface Obj {
    foo: string;
    bar: number;
  }

  interface Obj2 {
    foo:string
  }

  const b: Obj2 = {foo: 'foo', bar: 3}; //エラー
```

変数にオブジェクトを代入したい場合は、代入したい値を一度変数に入れてから代入しなければならないということ。
変数に入れて代入するか、そのまま代入するかで挙動が変わるのはとても違和感があるが、そういう仕様らしい。


####配列型

配列の型を表すための構文もtsには用意されている。
[]を用いる。例えば、number[]とすると、数値の配列を表す。

```
  const foo: number[] = [0, 1, 2, 3];
  foo.push(4); //pushで配列に要素を追加する
```

####関数型

関数の型を表すための構文もtsには用意されている。
例えば、（foo: string, bar: number）=> booleanのように表現される。
これは、第一引数としてstring型の、第二引数としてnumber型の引数をとり、返り値として、boolean型の値を返す関数の型という意味になる。

```
  const f: (foo: string)=> number = func;

  function func(arg: string): number {
    return Number(arg)
  }
```