なる早でTypescriptで（勉強用の）Next.jsサーバーを立ち上げる

# はじめに
この記事では、[React](https://ja.reactjs.org)の学習のために、[Typescript](https://www.typescriptlang.org)(.tsx)で[Next.js](https://nextjs.org)のサーバーを立てる方法を説明します。

- これは動くものを素早く作るためのチュートリアルです
- 設定ファイルをあえてほとんど書かないことで学習環境立ち上げの速さを実現させます
- Typescriptを手っ取り早く設定するために、執筆時点ではNext.jsの<ruby>canary<rt>カナリヤ</rt></ruby>バージョンを使います

<details><summary> <font color="#b01">なぜにこの記事が書かれたか</font> </summary><div>
主に理由は2つあります。

- Qiita書くと就活に有利らしいが、私はQiitaを書いたことがないために投稿の練習をしたいため
- 私が所属しているラボの後輩はWeb技術に興味津々で、彼らはインターンシップ選考で他者を蹴落とすために可及的速やかにTODOアプリなどを自分のGitHubに置きたく、何かしらのチュートリアルを望んでいるため

そこで、私の就職活動が終わり、彼らのインターンシップ選考が終わったこのタイミングの今こそあれ書くに最適と思い書き始めました。
</div></details>
<details><summary> <font color="#b01">筆者の環境</font> </summary><div>

* **OS:** macOS Mojave 10.14.5
* **ブラウザ:** Safari バージョン12.1.1 
* **[Node.js](https://nodejs.org/ja/):** v10.16.0
* **[Yarn]():** 1.15.2
</div></details>

今日作るもの： 読者の http://localhost:3000 に以下の内容を表示するサーバーをNext.js立てる。
![スクリーンショット 2019-06-30 16.19.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/cb6185f8-3ce9-3f00-896e-55aed0ac1f1c.png)

### インストールしなければならないモノ

本チュートリアルでは以下2点のソフトウェアを必要とします。それぞれ公式サイトのガイドを見て、よしなにインストールしましょう。

* **[Node.js](https://nodejs.org/ja/):** 推奨版
* **[Yarn](https://yarnpkg.com/lang/ja/):** 安定板

エディタは好きなのを使っていただければいいですが、[VSCode](https://code.visualstudio.com)や、ac.jpなどで終わる大学のメアドを持っている学生さんならば[WebStorm](https://www.jetbrains.com/webstorm/)を使うことを勧めるのが罪が無いかと思います。
<details><summary> <font color="#b01">プロキシの設定</font> </summary><div>

#### プロキシの設定

大学なりで開発しようとすると、```yarn```プロキシを設定しないとこれから叩くコマンドの```yarn add```が通らないかもしれません。

yarnのプロキシを設定するには以下のコマンドをターミナルで叩けば良いです。プロキシの設定において、ユーザー名やパスワードを必要としないならば、その箇所を抜いておいてください。

##### ユーザー名とパスワードが必要な時
```
yarn config set proxy http://ユーザー名:パスワード@プロキシのアドレス:プロキシのポート番号
yarn config set https-proxy http://ユーザー名:パスワード@プロキシのアドレス:プロキシのポート番号
```

##### ユーザー名が必要な時
```
yarn config set proxy http://ユーザー名@プロキシのアドレス:プロキシのポート番号
yarn config set https-proxy http://ユーザー名@プロキシのアドレス:プロキシのポート番号
```

##### ユーザー名とパスワードがいらない時
```
yarn config set proxy http://プロキシのアドレス:プロキシのポート番号
yarn config set https-proxy http://プロキシのアドレス:プロキシのポート番号
```


##### プロキシ設定の解除方法
```
yarn config delete proxy
yarn config delete https-proxy
```
</div></details>

# プロジェクトの準備

プログラムと作業ファイルを置きたいフォルダ<font color="#bbb">（ディレクトリ）</font>を何処ぞやに作ってください。

ターミナル<font color="#bbb">（あるいはコマンドプロンプト）</font>を開き、ターミナルのカレントディレクトリをそのフォルダにして下さい。

「カレントディレクトリ？何それ？」という方は、あとあと```cd```コマンドについて調べて頂くものとして、とりあえず以下の内容を試してください。
    1. ターミナルで```cd```と入力
    2. スペースキーを押す
    3. さっき作ったフォルダをドラッグ&ドロップ
    4. Enterキーを押す
    5. ```pwd```と入力しEnterを押した時に、そのフォルダのパスが表示されていればオッケー



このチュートリアルの以下のコマンドは、全てそのディレクトリ上で行われていることを前提とします。また、先ほど作ったフォルダをこのチュートリアルでは*プロジェクトルート*と呼ぶことにします。

----

# パッケージの追加

本チュートリアルで使うパッケージを*プロジェクトルート*に追加するために、*プロジェクトルート*上で以下のコマンドを入力します。

```
yarn add react react-dom next@canary
yarn add -D typescript @types/react @types/react-dom @types/node
```
<font color="#bbb">*/*TODO: Next.js 8.1.1がリリースされたら＠canaryを消す***/*</font>

コマンドが走り終わると、*プロジェクトルート*に以下のフォルダとファイルが出来上がります。

```
プロジェクトルート/
├── node_modules/ ⇦ なんかファイルいっぱい
├── package.json ⇦ 読めそう！
└── yarn.lock ⇦ 人が読めるファイルじゃない
```

気になるならば```package.json``` の中身を見てみましょう。　

以下は執筆時の```package.json```の内容です。

```json

{
  "dependencies": {
    "next": "^8.1.1-canary.63",
    "react": "^16.8.6",
    "react-dom": "^16.8.6"
  },
  "devDependencies": {
    "@types/node": "^12.0.10",
    "@types/react": "^16.8.22",
    "@types/react-dom": "^16.8.4",
    "typescript": "^3.5.2"
  }
}
```

```yarn add``` で追加したパッケージが```"dependencies"```にバージョンとともにリストされ、```yarn add -D```で追加したパッケージが```"devDependencies"```にリストされています。また実際のパッケージの中身と、それぞれのパッケージが依存するパッケージが```node_modules/```にドサッと入ります。

今後、もし```node_modules/```をバッと消しても、

```
yarn install
```
を叩けば```package.json```の内容<font color="#bbb">(と```yarn.lock```の内容)</font>をもとに ```node_modules/```に必要な中身を入れてくれます。つまり、```node_modules/```なしでよその人に作ったプロジェクトを渡しても、向こう側でインストールできるので、よそ様にプロジェクトを渡すときは```node_modules/```を消して渡す、gitには```node_modules/```をアップロードしないというのが作法です。


# Hello World
さて、ようやっとサーバーを立てます。

プロジェクトルートに```pages```という名前のフォルダを作り、その中に```index.tsx```を作ります。

```
プロジェクトルート/
├── node_modules/
├── pages/
│   └── index.tsx
├── package.json
└── yarn.lock
```

また、```index.tsx```に以下のプログラムを記述します。


```tsx:index.tsx
import {FC} from "react";

const Index: FC = () => (
    <p>Hello World!</p>
);

export default Index;
```

これで[Typescript](https://www.typescriptlang.org)(.tsx)でHello Worldのプログラムができました。では、サーバーを立ち上げましょう。以下のコマンドを入力してください、

```
yarn next
```

すると、以下のような表示が出て…

```
yarn run v1.15.2
warning package.json: No license field
$ [プロジェクトルート]/node_modules/.bin/next
[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
We detected TypeScript in your project and created a tsconfig.json file for you.

Your tsconfig.json has been populated with default values.

[ info ]  bundled successfully, waiting for typecheck results ...
[ ready ] compiled successfully (ready on http://localhost:3000)
```


やがて、 http://localhost:3000 にサーバーがreadyしたらしい表示になるので、アクセスしてみましょう。

![スクリーンショット 2019-06-30 17.10.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/05cef8ad-c760-9de4-12a2-fd97ee68081f.png)

おめでとうございます。Hello Worldが立ち上がりました。

#### 閉じ方
ターミナルに```[info]```なり```[ready]```なりが表示されているうちはサーバーが生きているので、サーバーを落としたければ、ターミナル上で<kbd><kbd>Ctrl</kbd>+<kbd>C</kbd></kbd>を入力してください。Windowsならば、コマンドプロンプト で<kbd><kbd>Ctrl</kbd>+<kbd>C</kbd></kbd>を押した後に```y```を入力することを求められるかもしれません。素直に従えば、サーバーを落とせます。

しかし、yarn nextで立ち上がるサーバーは開発用サーバーなので、サーバーを立ち上げたままファイルに変更を加えると、サーバーの内容にも変更が加わります。なので、本日、まだこのチュートリアルを続けるつもりならば、立ち上げてままにしてください。

##### なして```Next.js@canary```を使うたん？
ここの```Typescript```対応がゼロコンフィグだから。

# 解説
`Next.js`で立ち上げるサーバーでは```pages/```というフォルダと、```static/```というフォルダの内容が配信されます。
https://github.com/zeit/next.js/

また、特別に```pages/index.tsx```は http://localhost:3000 に配信されます。

先ほどのIndexの内容をわかるようにするために、```pages/kani.tsx```でほぼ等価なページを作ってみましょう。

```
プロジェクトルート/
├── node_modules/
├── pages/
│   ├── index.tsx
│   └── kani.tsx
├── package.json
└── yarn.lock
```

内容はこのようにします。

```tsx:kani.tsx
export default function Kani() {
    return <div>こんにちはかに</div>
}
```

するとhttp://localhost:3000/kani に
![スクリーンショット 2019-06-30 17.40.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/3509e71e-e058-e742-dd45-f46a48b00512.png)

が配信されます。`Next.js`では、戻り値が特別な関数を`export default`すると、ページが配信される仕組みになっています。

Typscript(Javascript)は変数に関数を代入できます。従って、このように書いても上と等価です。

```tsx
const KaniPage = function Kani() {
    return <div>こんにちはかに</div>
};
export default KaniPage; 
```

Typescriptは型をアノテーションすることができます。先ほどのコードにやたら丁寧にアノテーションをしてみましょう。

```tsx
import {FC, ReactElement} from "react";

const KaniPage:FC = function Kani():ReactElement {
    return <div>こんにちはかに</div>
};

export default KaniPage;
```
上記の意味は、変数```KaniPage```は```FC```型であり、関数```Kani```は引数なしで戻り値が```ReactElement```型であるということをアノテーションしています。

`ReactElement`型について、「さっきの関数はdiv要素を返しているやないか」と思われるかもしれませんが、.tsxファイル内では、

```html
<div>こんにちはかに</div>
```

は

```tsx
React.createElement('div', 'こんにちはかに');
```

に変換される仕組みになっています。`createElement`の戻り値が`ReactElement`なんだと思います。知らんけど。


> なのでimportに
> 
> ```tsx
> import * as React from "react";
> ```
>
> をつけるのが推奨されています。でも動いているから、ええや。

```FC```は**Functional Component**の略であり、関数型であり、```React```の`Component`の一種です。

`Next.js`は`pages/`以下のTypescriptファイルが```React```の`Component`を`export default`をしていたならば、それを表示する仕組みになっています。

次に行きましょう関数は「無名」でも構いません。つまり

```tsx
import {FC, ReactElement} from "react";

const KaniPage:FC = function():ReactElement {
    return <div>こんにちはかに</div>
};

export default KaniPage;
```
も等価です。

もっと行きましょう。予約語```function```を用いた関数定義は大抵、`arrow演算子`こと`=>`で書き換えられます。また、左辺値で`FC`に代入することを宣言しているので、`ReactElement`は冗長です。

```tsx
import {FC} from "react";

const KaniPage:FC = () => {
    return <div>こんにちはかに</div>
};

export default KaniPage;
```

また、即```retrun```するアロー関数は'{}'を'()'にすることで、`return`を省略できます。

つまり、

```tsx
import {FC} from "react";

const KaniPage: FC = () => (
    <div>こんにちはかに</div>
);

export default KaniPage;
```

これで、Indexに何が書いてあるか、なんとなくわかったでしょうか？

もっと気持ち悪く書くと、これでも動きますし、これを書く気分の日もあります。 

```tsx
export default () => (
    <div>こんにちはかに</div>
);
```

# Next.jsの軽い説明
`Next.js`を使ってできることを軽く説明します。
### 画像を配信する
先ほどのkaniページで、カニの画像を表示するようにしましょう。

まず、`static/`というフォルダを作り、その中に以下の`kani.png`を追加しましょう。
> ![kani.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/eb47dea4-4f2e-4cde-51be-b910e98bdc13.png)
> 5つ足カニ by Nanimono Demonai [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/deed.ja)

```
プロジェクトルート/
├── node_modules/
├── pages/
│   ├── index.tsx
│   └── kani.tsx
├── static/
│   └── kani.png
├── package.json
└── yarn.lock
```

`kani.tsx`を以下のように書き換えます。

```tsx:kani.tsx
import {FC} from "react";

const KaniPage: FC = () => (
    <div>
        <img src="/static/kani.png" alt=""/>
        <p>こんにちはかに</p>
    </div>
);

export default KaniPage;
```

このようなページが配信されました。
![スクリーンショット 2019-06-30 18.29.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/79f4e25e-84f9-a05a-dce1-bf7897fe4fb7.png)

### スタイルを設定する
このままではカニがやたらでかいです。スタイルを設定しましょう。

`Next.js`には`styled jsx`が同梱されているので、それでcssを設定してみます。


```tsx:kani.tsx
import {FC} from "react";

const KaniPage: FC = () => (
    <div>
        <img src="/static/kani.png" className="kani"/>
        <p>こんにちはかに</p>
        { /*language=CSS*/}
        <style jsx>{`
            .kani {
                max-width: 50px;
            }
        `}</style>
    </div>

);

export default KaniPage;
```
![スクリーンショット 2019-06-30 18.34.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/7561611d-01fd-ae24-95da-f511d4117998.png)

だいぶ小さくできました。
tsx上で`{}`で囲んだ部分は、Typescriptとして評価されます。さらに、`{/* */}`で囲んだ部分はコメントにできます。

### タイトルを設定する
今まで作ってきたものはタイトルが無名でした。カニのページを作っているのですから、ページのタイトルをカニにしましょう。`Next.js`では`<head>`要素を使うことができません。なので、`Next.js`で提供されている`<Head>`コンポーネントを使います。

```tsx:kani.tsx
import {FC} from "react";
import Head from "next/head";

const KaniPage: FC = () => (
    <>
        <Head>
            <title>カニのページ</title>
        </Head>
        <div>
            <img src="/static/kani.png" className="kani"/>
            <p>こんにちはかに</p>
            { /*language=CSS*/}

        </div>
        <style jsx>{`
            .kani {
                max-width: 50px;
            }
        `}</style>
    </>
);

export default KaniPage;
```
![スクリーンショット 2019-06-30 18.34.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/57631e6a-91f2-e421-61f1-e3d1e066ee69.png)

`<>`~`</>`という見慣れないタグがありますが、`React.Fragment`という名前のタグです。returnで戻せるタグを複数にすることができないので、一つにまとめるために使うものだと持ってください。

なので、`<>`~`</>`を抜くとどんなエラーが出るのか見てみましょう。

```tsx:これはエラー
import {FC} from "react";
import Head from "next/head";

const KaniPage: FC = () => (
        <Head>
            <title>カニのページ</title>
        </Head>
        <div>
        <img src="/static/kani.png" className="kani"/>
        <p>こんにちはかに</p>
        </div>
);

export default KaniPage;
```

http://localhost:3000/kani
![スクリーンショット 2019-06-30 18.55.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/15f645c2-6139-ca77-eccd-f14a44e4b006.png)

コンパイルエラーが出ましたね。とはいえ、「`<>`~`</>`を使うたらわ？」言うてはるで、素直に`<>`~`</>`で囲みまひょ。

# Typescriptの軽い説明

### 直に書く
ここまでの知識で冒頭の「今日作るもの」を作ってみましょう。


```tsx:index.tsx
import * as React from "react";
import Head from "next/head";

export default () => (
    <>
        <Head>
            <title>TitleはHelloWorld</title>
        </Head>
        <h1>Hello World</h1>
        <hr/>
        <p>こんにちは世界<br/>こんばんはカニ</p>
        <img src="/static/kani.png" alt="" className="kani"/>

        <p>1+1={1 + 1}</p>

        <ruby>世界<rt>World</rt></ruby>

        <li>hoge</li>
        <li>fuga</li>
        <li>piyo</li>

        {/*language=CSS*/}
        <style jsx>{`
            .kani {
                max-width: 50px;
            }
        `}</style>
    </>
);
```

### コンポーネントを分ける
直に書いた`<p>1+1={1 + 1}</p>`はしょうもないですね。もう少し面白くしましょう。

二つの数字`lv :number`,`rv :number`を受け取って`<p>lv+rv={lv + rv}</p>`を表示するコンポーネント`Sum`を作ってみましょう。

まず、*プロジェクトルート*に`components/`というディレクトリを作りその中に`myComponent.tsx`を作ります。`Next.js`でサーバーを作るときは`pages`と`static`という特別なディレクトリがありますが、それ以外には特別な役割がないので自由に作ることができます。


```
プロジェクトルート/
├── node_modules/
├── pages/
│   ├── index.tsx
│   └── kani.tsx
├── static/
│   └── kani.png
├── components/
│   └── myComponent.tsx
├── package.json
└── yarn.lock
```

早速、Typescriptらしく、`Sum`コンポーネントを定義していきましょう。なお、コンポーネント名は先頭大文字にしてください。

```tsx:myComponent.tsx
import {FC} from "react";

export interface SumProps {
    lv: number;
    rv: number;
}

export const Sum: FC<SumProps> = (props: SumProps) => (
    <p>{props.lv}+{props.rv}={props.lv + props.rv}</p>
);
```

`interface`はTypescriptの予約語でこの例では、`number`型の`lv`と`rv`をメンバーに持つような型を定義しています。`SumProps`型にパスするオブジェクトの例は以下です。

```tsx
const hoge: SumProps = {
    lv: 100,
    rv: 200
};
```

また今回定義した`Sum`は`props`を受け取る`FC`です。上の例も型付けが過剰です。右辺値はシンプルに以下のように書けます。

```tsx
export const Sum: FC<SumProps> = props => (
    <p>{props.lv}+{props.rv}={props.lv + props.rv}</p>
);
```

これを`pages/sumTest.tsx`で使ってみましょう。`sumTest.tsx`を作成し、以下のように利用します。

```
プロジェクトルート/
├── node_modules/
├── pages/
│   ├── index.tsx
│   ├── kani.tsx
│   └── sumTest.tsx
├── static/
│   └── kani.png
├── components/
│   └── myComponent.tsx
├── package.json
└── yarn.lock
```

```tsx:sumTest.tsx
import {Sum} from "../components/myComponent";

export default () => (
    <>
        <Sum lv={1} rv={1}/>
        <Sum lv={100} rv={73}/>
        <Sum lv={-300} rv={50}/>
        <Sum lv={100} rv={-50}/>
    </>
)
```
![スクリーンショット 2019-06-30 19.53.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/682aa128-455d-8bc5-1df4-f766d1333142.png)
いい感じですね。

ただし、
> 100+-50=50

が気味が悪いです。あとあと直すようにしましょう。気張ってください。


### map関数の素振り
```html
<li>hoge</li>
<li>fuga</li>
<li>piyo</li>
```
この部分を
文字列配列`texts :string[]`を受け取って`<><li>x_1</li><li>x_2</li>...<li>x_n</li></>`を表示するコンポーネント`TextList`を作ってみましょう。

```tsx:myComponent.tsx
//追記

export interface TextListProps {
    texts: string[];
}

export const TextList: FC<TextListProps> = props => (
    <>
        {props.texts.map(e => <li key={e}>{e}</li>)}
    </>
);


```

```tsx:listTest.tsx
import {TextList} from "../components/myComponent";

export default ()=>(
    <>
        <TextList texts={["hoge","fuga","piyo"]}/>
    </>
);
```

![スクリーンショット 2019-06-30 20.05.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/ef74dd1c-4433-42c6-1e87-6eb25f7b8359.png)

いい感じですね。配列を`React.Element`配列に写像することでリストを表現するコンポーネントなどが作れます。そのために、TypescriptのArrayに備え付けの`map`関数が多々用いられます。

今回は、mapする際に、一番外側の要素にkey属性をつけています。このkey属性の中身に兄弟となる`React.Element`の中でユニークな値(`string`型でも`number`型でも)をつけることで、`React`のパフォーマンスが上がります。どうするのが良いのかはよそで調べましょう。

**参考:** [リストと key – React](https://ja.reactjs.org/docs/lists-and-keys.html)

### childrenの素振り（子供を振り回してはならない）

これは天下り的に説明したほうがわかりやすいかもしれません。

```tsx:myComponent.tsx
//import {FC} from "react"; 取る
import {FC, ReactNode} from "react"; //書き換え

//中略
//追記
import Head from "next/head";

export interface LayoutProps {
    children: ReactNode;
    title: string;
}

export const Layout: FC<LayoutProps> = props => (
    <>
        <Head>
            <title>Titleは{props.title}</title>
        </Head>
        <h1>{props.title}</h1>
        <hr/>
        <div>
            {props.children}
        </div>
    </>
);
```

```tsx:layoutTest.tsx
import {Layout} from "../components/myComponent";

export default ()=>(
    <Layout title={"レイアウトテスト"}>
        <div>
            <p>レイアウトの子要素です</p>
            <p> Hello</p>
        </div>
    </Layout>
)
```

![スクリーンショット 2019-06-30 20.26.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/918f210c-9066-33cc-922f-f9ffd9b5d3cb.png)

つまり、`props`に`children: ReactNode;`を取ると、子要素が取れます。

### 合体

今日つくるページは、今まで作ったコンポーネントでこのように書くことができます。

```tsx:index.tsx
import {Layout, Sum, TextList} from "../components/myComponent";

export default () => (
    <Layout title={"Hello World"}>
        <p>こんにちは世界<br/>こんばんはカニ</p>
        <img src="/static/kani.png" alt="" className="kani"/>

        <Sum lv={2} rv={1}/>
        <ruby>世界
            <rt>World</rt>
        </ruby>

        <TextList texts={["hoge", "fuga", "piyo"]}/>

        { /*language=CSS*/}
        <style jsx>{`
            .kani {
                max-width: 50px;
            }
        `}</style>
    </Layout>
);
```

# まとめ
* Next.jsの8.1.1から、Typescriptがすごく書きやすくなりそう

**続き**

* [なる早でTypescript + Next + MobX + mobx-react-lite でグリグリ動く「買い物リスト」みたいなのを作る
](https://qiita.com/NanimonoDemonai/items/141b99f316190b265821)