TypescriptでJavascriptライブラリーを使う方法

####Typescriptはnode_modulesを見てるか？
結論：見てるとき、見てないときがあります。

"moduleResolution":

'node' (Node.js) か 'classic'の値を取ることができます。

```ts
import axios from 'axios';
```

"moduleResolution": "node"にしておくと、↑のように、
相対パスではない書き方でインポートしたときに、node_modulesを見に行きます。

"moduleResolution": "classic"にしておくと、カレントディレクトリにaxiosないかなー、
と見に行くだけになります。

####Webpackはnode_modulesを見てるか？
見てます。

node_modulesの中にあるaxiosの中の、d.tsファイルを見にいきます。

#.d.ts
d　＝　declarations　＝　宣言

この拡張子のファイルを、型定義ファイルと言ったりします。

型の情報のみがザーッと入っています。

↓としておくと、勝手にdeclarationsファイルが作られます。

```tsconfig.json
"declaration": true
```

型定義ファイル（.d.tsファイルが存在しない場合も高確率であります。）


#DefinitelyTyped 
TypeScript 用の型定義リポジトリです。

昨今、特にフロントエンドでは TypeScript を使うのが当たり前となったが、
まだまだ過去の遺産、型定義すらない JavaScript ライブラリも多いのです。
型定義がなければ自前で書く必要があります。

「型定義を書く」とは、基本的に公式ドキュメントを TypeScript に変換することです。

#####＠typesパッケージをインストールして、既存の型定義ファイルを使う方法

↓のようにimportしようとしたが、
node_modules/lodash/にd.tsファイル（Typescriptファイル）がなかった場合、

```ts
import _ from 'lodash';
```

まず模索すべきは、「誰かがこの型定義ファイルをすでに作っていないか？」です。

Typescriptは、node_modules/lodash/の次に、node_modules/＠typesを見にいきます。
なので、仮にlodashの型定義ファイルが存在すれば、
インストールしてnode_modules/＠types/に入れてあげれば良いのです。

googleで＠types/lodashのような結果があれば、大体あります。
[![Image from Gyazo](https://i.gyazo.com/b162a0cd9e1d596c63c145c9423321a2.png)](https://gyazo.com/b162a0cd9e1d596c63c145c9423321a2)

↓のようなコマンドで入れてあげます。

```
 % npm install --save-dev @types/lodash
```


TypescriptでJavascriptライブラリーを使いたいときは、
まず、それのTypescript型定義ファイルが、
パッケージ（node_modules/それの名前/d.ts）にあるかどうかを確認して、
なかったらnode_modules/＠typesに入れるものをgoogleで探す。

#型定義ファイルを作る方法

それでもなかったら、**直接型定義ファイルを書く**しかありません。

```library.ts
import _ from 'lodash';
```

↓declare module 'lodash' {　}で、lodashの型を指定することができます。

```lodash.d.ts
declare module 'lodash' {
  export function shuffle<T>(arr:  T[]): T[]
}
```

↑これでlodashは、importされたら、shuffleというメソッドがあって、
<T>(arr:  T[　]): T[　]という型だよ。とTypescriptに伝えることができます。

#CDNで型定義ファイルを読み込む
これまでは、npm経由で型定義ファイルを読み込んでいました。
次に、CDN経由で、scriptから読み込む方法を見ていきます。

↓Lodash公式ページからCDN copiesをクリックして、先頭のHTMLをコピーして貼り付けます。

https://lodash.com/

```index.html
  <link rel="stylesheet" href="style.css">

  //↓これ
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
 
  <script src="dist/bundle.js" defer></script>
```

↓その後、型を指定してあげるとエラーが消えます。

```tslodash.ts
declare module 'lodash' {
  export function shuffle<T>(arr:  T[]): T[]
}

interface Lodash {
  shuffle<T>(arr:  T[]): T[]
}

declare const _: Lodash
```

#namespace
名前空間です。名前の衝突を防ぐ役割があります。
しかし、import, exportを優先するように言われており、あまり使う機会はありません。

↓{　 }内のnameを外で使えます。

```library.ts
namespace myApp {
  const hello = 'hello in namespace';
  export const name = 'Quill';
}

const hello = myApp.name
```

↓namespaceで型を定義する方法

```library.ts
namespace myApp {
  const hello = 'hello in namespace';
  export const name = 'Quill';
  export interface Nameable {
    name: string;
  }
}

let nameable: myApp.Nameable;
```

〜.〜のような型があれば、基本的にはnamespaceが使われていると思ってください。

#declear
「どこかでその変数が使われてるよ」という意味です。
↓constと書いてありますが、実際にメモリを用意して変数を作ってるわけではなく、
↓どこかで使われているよ。というのをお知らせしてるだけです。

```axios/index.ts
declare const axios: AxiosStatic;

export default axios;
```

ambient declaration（アンビエント宣言）と呼ばれたりします。

ambient　＝　周囲、環境

#lodashの型定義ファイルの中身を見てみる

↓「トリプルスラッシュディレクティブ」
↓　ts → jsに変換したときに無くなります。


```lodash/index.ts
/// <reference path="./common/common.d.ts" />
```

↓node.js用のexport文。

```lodash/index.ts
export = _;
```

↓importを使わずに、直接読み込みなどをしたときに、_を使えるようにするための決まり文句。

```lodash/index.ts
export as namespace _;
```

####declare global {　}

declare global {　}の中は、
全部自動的にアンビエント宣言になり、かつグローバルで使えるようになります。

#同じ名前の値・型・namespace
Typescriptの概念では、主にデータの種類が３種類あります。
それが「値・型・namespace」です。
↓さらに、それら３つは共存することもできます。

```library.ts
let name: string;
interface name {}
namespace name{}
```

値同士・型同士はダメです。

#####例外

↓interface同士は共存できます。

```library.ts
interface name {
  first: string
}
interface name {
  second: number
}
```

↓classとinterfaceも共存できます。

```library.ts
class name {}
interface name {
  first: string
}
interface name {
  second: number
}
```

classは、interfaceも定義していると考えられます。
classが定義する型が、interfaceのような扱いを受けるからです。

↓namespace同士も共存できます。

```library.ts
namespace name{
  const first: string = 'Peter';
}
namespace name{
  const first: string = 'Peter';
}
```

mergeされて１つになるイメージです。

同名のプロパティは、型が違うとエラーになります。
同名のメソッドはオーバーロードされます。


・値を含んだnamespaceと変数はダメです。