syakoo's Lab

技術ブログやちょっと気合の入った記事を残すブログ

Typescript+React+FirebaseでSPAを作ってみた

f:id:syakoo:20190831201843p:plain

はじめに

Typescript+React+Firebaseを使ってSPA(Single Page Application)を作ってみました。そのWebアプリの紹介と感想を残します。

魔法陣タイムアタック

作ったアプリはMagic Squareという魔法陣を解くタイムを競うアプリです。 リンクはこちら(Magic Square)

ソースコード

ソースコードこちらにあります。が、TypeScript+React+FirebaseでSPAを作る練習で作ったアプリなので、参考になるかは微妙です。

最新版

Webアプリ: https://magic-square.firebaseapp.com

Git hub: https://github.com/syakoo/MagicSquare/tree/master

仕様(?)

Reduxは使わない(使えない)

そもそもTypeScriptもReactも触って一ヵ月くらいなので、Reduxまで勉強していたら目が回りそうだと思ったので使わない方針で作りました。今現在は使っておけばもっといいのが作れたなぁと後悔しています。

ReactHookを積極的に使う

ReactHookはクラスを使わなくてもstateなどのふるまいができる機能です。今回で初めて使ったのでできるだけ積極的に使うようにしました。

ログインさせない(できない)

SPAを初めて作るということで一番不思議に思ってたことは、「クライアントで動くのにセキュリティ大丈夫なのか?」ということです。当然そんなこと考える余裕が作成中にはなかったので、ログインしない方針にしました。個人的に一番大事な課題です。

手軽に参加しやすいアプリ(にしたかった)

タイムを競うので当然プレイ人数が多ければ多いほど熱くなると思ったので、手軽に参加しやすいようにを軸に考えて作成しました。具体的には - シンプルレイアウト - Noログイン - スマホ向けに対応

等です。レスポンシブデザインの大変さも学びました。

さいごに

もちろん、自分の力じゃあんな素敵なUIは作れません。相談に乗ってくれた友人に感謝しています。

魔法陣について少し考えてみる(#2 大きな命題)

はじめに

今作っているゲームのために魔法陣について少し深く考えてみた記録。数学っぽく固く書きたくないので、できるだけ砕いて説明していきます。

ここで用いる魔法陣は1~9の数字を3×3のマスに縦横斜めの和が一定になるように配置した方陣を想定しています(他の方式があるか知らないけれど)。

このページは少し難しめな内容になっています。前回の記事は優しく説明しているかと思うので、前回の記事も閲覧していただけると幸いです。(前回の記事)

考えてみる命題

今回は大きな命題を考えていきます。その命題は

3×3の魔法陣は対称形を除いて一つしか存在しない

ということです。これを証明するために中くらいの命題を用意します。

それではこれらの予想が正しいか考えていきます。もちろん前回の記事の小さな命題も使います。

f:id:syakoo:20190831135135p:plain

証明

最初にも述べていますが、厳密な証明はしないので他サイトを参考にしてください。

この証明には剰余(Modulo)と言われる考え方の基礎的な知識が必要です。できるだけわかりやすく説明しますが、途中の演算等でつまずいたら剰余について軽く触れることをオススメします。

3×3の魔法陣の角に入る数字は決まっている

まず、1~9の数字をー1をして3で割った商と余りのペアに変換します。


\begin{align}
1 - 1 &= 0 = 0 \,\,余り\, 0 => (0,0) \\
2 - 1 &= 1 = 0 \,\,余り\, 1 => (0,1) \\
3 - 1 &= 2 = 0 \,\,余り\, 2 => (0,2) \\
4 - 1 &= 3 = 1 \,\,余り\, 0 => (1,0) \\
5 - 1 &= 4 = 1 \,\,余り\, 1 => (1,1) \\
6 - 1 &= 5 = 1 \,\,余り\, 2 => (1,2) \\
7 - 1 &= 6 = 2 \,\,余り\, 0 => (2,0) \\
8 - 1 &= 7 = 2 \,\,余り\, 1 => (2,1) \\
9 - 1 &= 8 = 2 \,\,余り\, 2 => (2,2) \\
\end{align}

これでどうなったのかというと、1~9の数字を3で割った商3で割った余りでグループ分けできるようになります。

f:id:syakoo:20190831135240p:plain
グループ分け
変換したことで、前回の記事の命題にどんな変化があったかを考えます。命題の根本的な考え方は変わらず、値だけが変わります。

変換前 変換後
魔法陣全体の合計値 45 36 (-9)
一列の合計 15 12 (-3)
中央の値 5 4 (-1)

これから進んでいきます。

一列の合計を3で割った余りを等しくするためには、2つの方法があります。

  1. 余りをそれぞれ0、1、2で集める
  2. 余りが0,1,2のペアを集める

f:id:syakoo:20190831135423p:plain

しかし、1.については合計を3で割った余りは等しいですが、合計自体が等しくなる(12になる)のは余りが1の時のみです。

なぜ余りが1の時のみなのか簡単に説明すると、中心が4ということに関係しています。

同じく、合計が等しくなる(12になる)のは、上の条件に加えて

  1. 商をそれぞれ0,1,2で集める
  2. 商が0,1,2のペアを集める

これも同様に、商が1の時のみ1.が成功します。これはそれほど難しくなく、商が0、1、2と変わることで元々の数字は0、3、6と大きく変わっていくため、均等に配置するにはバラつかせるしかありません。

これを踏まえたうえで魔法陣について考えてみます。

まず、中心は4で確定なので配置します。カッコは商と余りで分けた表現です。

_ (_, _)_ (_, _)_ (_, _)
_ (_, _)4 (1, 1)_ (_, _)
_ (_, _)_ (_, _)_ (_, _)

次に、余りを配置していきます。余りが1のみ連続で配置が可能でそれ以外は縦横斜めに関してバラバラに配置する必要があるのでこんな感じになります。

_ (_, 1)_ (_, 2)_ (_, 0)
_ (_, 0)4 (1, 1)_ (_, 2)
_ (_, 2)_ (_, 0)_ (_, 1)

0と2は逆に配置しても大丈夫です。ただ、角に関しては両方1の角のペア0と2のペアのどちらかに確定します。

最後に、商を配置していきます。余りの時と同様に商が1のみ連続で配置が可能でそれ以外は縦横斜めに関してバラバラに配置する必要がありまた同じぺア(商, 余り)の数字が出ないように配置します。

_ (0, 1)_ (2, 2)_ (1, 0)
_ (2, 0)4 (1, 1)_ (0, 2)
_ (1, 2)_ (0, 0)_ (2, 1)

これも余りの時と同様に、角に関しては両方1の角のペア0と2のペアのどちらかに確定します。

最後に、商と余りから値を出します。3で割る除算だったので、 3×(商)+(余り)ですね。

1 (0, 1)8 (2, 2)3 (1, 0)
6 (2, 0)4 (1, 1)2 (0, 2)
5 (1, 2)0 (0, 0)7 (2, 1)

以上より、角に関して 3 (1, 0)、5 (1, 2)、1 (0, 1)、7 (2, 1)の4つが配置されることは確定であり、前回の記事の命題3.より3と5、1と7はペアとしてそれぞれ対角線上に配置される

最初に変換で(-1)していたので、元に戻して(+1)結論を書くと、

角に関して 4、6、2、8の4つが配置されることは確定であり、4と6、2と8はペアとしてそれぞれ対角線上に配置される


上の命題を用いて最後の問題を証明します。

3×3の魔法陣は対称形を除いて一つしか存在しない

前回の記事の命題1.より間の数字も角が確定すれば確定します。

2?4
?5?
6?8

つまり、角が配置されれば魔法陣は完成するため、魔法陣は角の配置によって形が変わります。

ここで、上の命題より、4と6、2と8の対称移動にのみ角は変化するため、3×3の魔法陣は対称形を除いて一つしか存在しないことが言えます

f:id:syakoo:20190831135651p:plain
角のパターン

おわりに

これで3×3の魔法陣についての考察はたぶん終わりです。シンプルなのに非常に深いゲームでした。ちなみに、(1, 0)のようなペアを重ならないように配置するものはギリシアラテン方陣という名称があります。

魔法陣について少し考えてみる(#1 簡単な性質)

はじめに

今作っているゲームのために魔法陣について少し考えてみた記録。数学っぽく固く書きたくないので、できるだけ砕いて説明していきます。

ここで用いる魔法陣は1~9の数字を3×3のマスに縦横斜めの和が一定になるように配置した方陣を想定しています(他の方式があるか知らないけれど)。

考えてみる命題

命題は、魔法陣を見てこういう性質があるんじゃないかっていうのを予想してまとめたものです。小さな気付きをまとめることで大きな性質が見えてくることがあるので、今回は小さな命題を用意しておきます。

それではこれらの予想が正しいか考えていきます。

証明

最初にも述べていますが、厳密な証明はしないので他サイトを参考にしてください。

1. 各行、各列の和はどの魔法陣でも同じである

まず、各行を考えてみます。 1~9の数字が一回ずつ使われているから、全部のマスの合計は


1+2+3+4+5+6+7+8+9=45

です。魔法陣の定義から、各行の和は同じで3行あることから


45/3=15

各行の和は15となり、どの魔法陣でも同じであることが言えます。

各列についても同様にして、各列の和は15になり予想は正しいことが言えました。


2. 中央の数字はどの魔法陣でも同じ5である

中心の数字を特定していきます。適当な魔法陣を持ってきて、下のように文字に置き換えます。

 a  b  c
 d  e  f
 g  h  i

中心を通る縦横斜めの和は上の命題1.から


b+e+h=15


d+e+f=15

斜め


\begin{align}
a+e+i &= 15 \\
c+e+g &= 15
\end{align}

そう、全て15になりますね。そしてこれを全部足すと...


\begin{align}
(b+e+h)+(d+e+f)+(a+e+i)+(c+e+g) &=15+15+15+15 \\
a+b+c+d+4e+f+g+h+i &=60 \\
(a+b+c+d+e+f+g+h+i)+3e &=60
\end{align}

つまり、魔法陣全体の和+中央×3になってますね!魔法陣全体の和は45なので、


\begin{align}
3e &= 15 \\
e &= 5
\end{align}

 eつまり、中央のマスは5であることが言えました。


3. どの魔法陣でも中央を挟んだ対(ペア)は同じである

まず、魔法陣の定義と証明した命題1.から


\begin{align}
{(中央を挟んだ対の和)}+{中央}=15
\end{align}

であることがどの場合でも成り立ちますね。ここから攻めていきます。 中央の数字は命題2.より5であるから、


\begin{align}
{(中央を挟んだ対の和)}+5 &= 15 \\
{(中央を挟んだ対の和)} &= 10
\end{align}

これで、対の和が必ず10になることが言えますよね。つまり、片方が決まれば対のもう片方も一つに求まるということです。 よって、どの魔法陣でも同じペアを取ることがわかりました。


おわりに

今回は簡単な魔法陣の性質について考えてみました。こういうゲームにも色々な性質があると思うと面白いですね。

TypeScript+React+FirebaseでWebアプリを作ってみる(#1 動作確認)

はじめに

今回は詳しく説明するというより、ブログぽく備忘録として残すのが目的です。

SPA(Single Page Application)をつくる

今回は今まで作ってみたかったSPA(Single Page Application)をTypeScript React Firebaseを使って作っていきます。SPAとは、言葉の通り単一のWebページから構成されるアプリです。

ja.wikipedia.org

サーバーの負担が少なくなるということが大きいメリットになると思います。

なんのアプリを作るかというと、最終的には魔法陣を使った簡単なゲームを作りたいと思います。

1. 環境構築(TypeScript+React)

まずは環境構築です。いつもここでかなり時間をかけていて大変なので今回はコマンドに頼ってちゃちゃっと作ります。作業フォルダに移動して次のコマンドを入力。

$ npx create-react-app magic-square --typescript

結構時間がかかりますが、これで環境構築してくれます。終了したら一旦動作確認をします。

$ npm start

これでlocalhostでReactのロゴが回転しているのを確認をします。

f:id:syakoo:20190825193826p:plain
動作確認(typescript+react)

2. Reactの動作確認

一応Reactが動いているのは確認できていますが、Reactっぽくないので少しコードをいじります。 以下のサイトを参考にしました。

qrunch.net

magic_square/srcCount.tsxIncrement.tsxを作成して以下のコードを記述。

magic_square/src/App.tsx

import React, { useState } from "react";
import "./App.css";

// 自作Componentのインポート
import Count from "./Count";
import Increment from "./Increment";

// 全体のComponent
const App: React.FC = () => {
  // ReactHookを使う
  const [count, setCount] = useState(0);

  return (
    <div className="App">
      <Count count={count} />
      <Increment count={count} setCount={setCount} />
    </div>
  );
};

export default App;

magic_square/src/Count.tsx

import React from "react";

// CountのComponent.今回は出力するだけ
const Count: React.FC<{ count: number }> = ({ count }) => {
  return <h1>{count}</h1>;
};

// Componentのエクスポート
export default Count;

magic_square/src/Increment.tsx

import React, { Dispatch } from "react";

// インクリメントボタンのComponent
const Increment: React.FC<{ count: number; setCount: Dispatch<number> }> = ({
  count,
  setCount
}) => {
  // インクリメント処理
  const clickEventHandler = () => {
    setCount(count + 1);
  };

  // インクリメントボタンのUI
  return <button onClick={clickEventHandler}>INCREMENT</button>;
};

// Componentをエクスポート
export default Increment;

動作確認をします。

$ npm start

ボタンをクリックしたらカウントアップしていれば大丈夫です。

3. Firebaseで動作確認

最後にFirebaseで動作確認します。Firebaseのコンソールに移動して、新しいプロジェクトを作成します。今回はMagicSquareという名前にします。

f:id:syakoo:20190825193941p:plain

そして、プロジェクトに入って</>のマークをクリックしてウェブアプリを作成します。すると、Firebase SDK snippetにコードがあるので、それをmagic_square/src/firebase.tsに記述。(firebase.tsは作成してください)

import * as firebase from 'firebase/app';
import "firebase/firestore";


const firebaseConfig = {
    apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXX",
    authDomain: "XXXXXXXXXXXXXXXXXXXXXXXXXX",
    databaseURL: "https://magicsquare-cb1cf.firebaseio.com",
    projectId: "magicsquare-cb1cf",
    storageBucket: "",
    messagingSenderId: "86021422730",
    appId: "1:86021422730:web:f2b6a3e8fe162731"
};

firebase.initializeApp(firebaseConfig);

export const fireStore = firebase.firestore();

いまはエラーが発生しているかもしれませんが、この作業フォルダにFirebaseを設定していないだけなので気にしないで大丈夫です。

次に、この作業フォルダにFirebaseを設定していきます。 まずはfirebase-toolsをグローバルにインストール

$ npm i -g firebase-tools

次に今入れたfirebaseにアカウントでログインします。

$ firebase login

そして作業フォルダでfirebaseを初期化します。

$ firebase init

次の内容で初期化しました。

  • DatabaseとHostingを使用
  • MagicSquare(作成したプロジェクト)を選択
  • SPA(Single Page Application)として作成
  • index.htmlは上書きしない

初期化が終わったら、firebaseをローカルにインストール

$ npm i firebase --save

これで先ほどのエラーはなくなったと思います。動作確認をしていきます。まずはビルドします。

$ npm run build

するとbuildファイルが作成されたことがわかります。次にmagic_square/firebase.jsonのpublicをbuildに変更。最後にデプロイする場合はfirebase deploy、ローカルで確認する場合はfirebase serveで動作確認をします。

f:id:syakoo:20190825194027p:plain
動作確認(typescript+react+firebase)

これで終わります。

おわりに

次は実際にアプリを作っていく予定ですが、ブログに残すかは微妙です。

TypeScriptを勉強してみる(#2 webpack)

f:id:syakoo:20190815173938p:plain

1. はじめに

前からTypeScriptに運命を感じていたので、布教していきます(TS初心者)。前回の記事に書いていることを今回は割愛しているかと思うので、よろしければ前回の記事も観ていってください。TypeScriptを勉強してみる(#1 tsc) - syakoo's Lab

2. Webpackとは...?

さて、前回はtscを用いることでTypeScriptJavaScriptにトランスパイルし、実際にhtml上で動作確認をしました。それでイントロダクションを終了していいかと言われれば、まだTypeScriptのありがたみに触れていないとおもいます。せっかくTypeScriptを使っているので、オブジェクト毎にファイルを管理、したいですよね?

ということで今回使用するのはWebpack

webpack.js.org

これはJSファイルをまとめるモジュールハンドラで、ファイルの依存関係をまとめてくれます。つまり、別のファイルからオブジェクトを引っ張ってきたり、出力したりすることが可能になります。

CommonJSを使うことでtscコマンドからもモジュールを管理できるみたいですが、webpack記事(下にもリンクがあります)が非常にわかりやすかったので今回はwebpackを進めていきたいと思います。

3. 環境構築

前回と同じくNode.jsのパッケージマネージャであるnpmを使って環境構築をしていきます。公式ホームページからNode.jsをインストールしてnpmコマンドを叩けれるようにしておきましょう。

まずは、作業ディレクトリに移動して、パッケージマネージャを初期化

$ npm init

初期設定を聞かれますが、Enter連打で飛ばしても構いません。

次に、npmを用いてローカルのディレクトリに以下のパッケージをインストール。

typescript

$ npm i typescript --save

ts-loader

$ npm i ts-loader --save

webpack

$ npm i webpack --save

webpack-cli

$ npm i webpack-cli --save

しっかりインストールされているかが初期化(init)した際に作られたpackage.jsonを確認すると分かります。

{
  "name": "webpack-tutorial",
  "version": "1.0.0",
  "description": "tutorial",
  "main": "main.js",
  "author": "",
  "license": "ISC",
  // 追記-----------------------------
  "scripts": {
    "build": "webpack",
    "watch": "webpack -w"
  },
  // ---------------------------------
  "dependencies": {
    "ts-loader": "^6.0.4",
    "typescript": "^3.5.3",
    "webpack": "^4.39.2",
    "webpack-cli": "^3.3.6"
  }
}

続いて、tsconfig.jsonwebpack.config.jsを作成して以下のように書いていきます。

tsconfig.json

{
    "compilerOptions": {
      "sourceMap": true,
      "target": "es5",
      "module": "es2015",
    }
}

webpack.config.js

module.exports = {
  mode: "development", //開発モード
  entry: "./typescript/main.ts",
  output: {
    path: `${__dirname}/javascript`,
    filename: "main.js"
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: "ts-loader"
      }
    ]
  },
  resolve: {
    extensions: [".ts"]
  }
};

これで、npm run buildと打つと./typescript/main.tsから./javascript/main.jsが生成されます。

4. TypeScriptを書いてみる

ディレクトリ構成はこちら。

f:id:syakoo:20190815175306p:plain
ディレクトリ構成

前回と同じようにJavaScriptのファイルは./javascriptTypeScriptのファイルは./typescriptに書いていきます。helloWorld.tsmain.tsに以下のコードを記述。

./typescript/helloWorld.ts

function helloWorld(name: string): void {
    let message = name + ': Hello TypeScript :)'
    
    console.log(message);
}

// helloWorld()をファイル外にエクスポートする
export default helloWorld;

./typescript/main.ts

import helloWorld from './helloWorld';

// helloWorld.ts内の関数を呼び出す。
helloWorld('Syakoo');

コメントにもありますが、helloWorld.tshelloWorld()という関数をエクスポートして、main.tsでその関数を呼び出しています。

5. 動作確認

webpack.config.jsで書いている通り、main.tsをメインファイルとしてトランスパイルしていきます。以下のコマンドを実行。

$ npm run build

すると、./javascript/main.jsが生成されます。中身を見てみると...

f:id:syakoo:20190815175418p:plain
main.js

思ったより多く追記されていることがわかります(113行まであります)。それでは動作確認をしていきましょう。前回と同じく、Node.jsを用いてターミナル上で確認できます。

$ node ./javascript/main.js
Syakoo: Hello TypeScript :)

ちゃんと出力されました。

6. ちなみに

上ではwebpack.config.jsmodedevelopmentを選択していました。これは、デバッグする時にJSTSをリンクさせるためです。 このモードをproductionにすると、最適化された状態で出力されます。そちらの動作確認もしていきましょう。

まず、モードの変更

webpack.config.js

module.exports = {
  mode: "production", //変更点
  entry: "./typescript/main.ts",
  output: {
    path: `${__dirname}/javascript`,
    filename: "main.js"
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: "ts-loader"
      }
    ]
  },
  resolve: {
    extensions: [".ts"]
  }
};

そしてトランスパイル

$ npm run build

できたmain.jsを確認すると...

f:id:syakoo:20190815175500p:plain
main.js

一行でまとめられていかにも圧縮されていますね。これで動くのか確認してみる

$ node ./javascript/main.js
Syakoo: Hello TypeScript :)

ちゃんと動きますね。これで終わります。

7. さいごに

今回でオブジェクト毎にファイルを分けれるようになったと思うので、これからTypeScriptを使って楽しく(?)開発していきましょう。 これからはハマったところや気付いたことを記事にしていければなと思っています。

8. 参考記事

↓ 非常に参考になりました。ありがとうございます。

最新版TypeScript+webpack 4の環境構築まとめ(React, Vue.js, Three.jsのサンプル付き - ics.media)

TypeScriptを勉強してみる(#1 tsc)

f:id:syakoo:20190807140200p:plain

1. はじめに

前からTypeScriptに運命を感じていたので、チュートリアルを進めながら布教していきます。

目次は以下の感じです。

2. TypeScriptとは

www.typescriptlang.org (↑公式ページ)

TypeScript はマイクロソフトによって開発され、メンテナンスされているフリーでオープンソースプログラミング言語である。TypeScriptはJavaScriptに対して、省略も可能な静的型付けとクラスベースオブジェクト指向を加えた厳密なスーパーセットとなっている。(引用: https://ja.wikipedia.org/wiki/TypeScript)

簡単に言うと、JavaScriptは書いたらそのまま実行できるが、TypeScriptは一度トランスパイルといってJavaScriptに変換されてから実行できるようになります。

あれ、じゃーJavaScriptでよくない?と思うかもしれないが、様々な利点があります。個人的に今思い浮かぶ利点(TS初心者だけど)を上げていこうと思います。

  • 静的型付けより、クラスや関数がより厳格化できる。

特に共同開発などで進めると、このクラス使えばいいや見たいなノリでしっかり理解していない関数を呼び出すときがある(と思う)。その時に、型付けされていればバグを未然に防ぐことができる。

  • 一度トランスパイルする工程を作ることにより、先にバグを発見できる。

そのまま。動作のバグは動作確認でしかできないけれど、簡単なバグは実行前に確認出来たらうれしいです。

  • トランスパイルは最適化されたJSに変換される。

トランスパイルの設定次第で、ES5ES6などのブラウザのバージョンに合わせてJSに変換してくれるので、全部書き直す必要がないです。

...このままだと、文字がズラーーーって並ぶだけで何も面白くないと思うので、利点はこのくらいにしてチュートリアルを見ながらやっていきます。

3. 環境構築

まず、公式ページからNode.jsをインストールします。Node.jsってサーバーサイドのJSって聞いたけど関係あるの?と思うかもしれないですけど、Node.jsをインストールするとnpm(Node Package Manager)というパッケージが豊富なツールが手に入るので、JSをやりたい人には割と必須なモノです。

JavaScriptnpmPythoncondaは似ていますが、パッケージの管理の仕方に違いがあります。

言語 パッケージの管理の仕方
npm Javascript ディレクト
conda Python conda環境

上にもある通り、condaは環境を作ってその中でパッケージをインストールしていきますが、npmディレクトリ毎にパッケージをインストールします。 ベースの環境もcondaだとbasenpmだとglobalとなります。

それでは、TypeScriptの環境を作っていきます。まずは作業用フォルダを適当に作ってそこに入ります。 そしてこのコマンドをそのディレクトリで入力。

$ npm i -g typescript

iはinstallのiです。installと入力しても大丈夫です。また、-gはグローバルにインストールということですので、どのディレクトリでもtypescriptがインストールされた状態になります。 このコマンドを打って、バージョンか帰ってきたら成功です。

$ tsc -v
Version 3.5.3

このtscっていうのが、トランスパイル(TS=>JS)をするためのコマンドです。(多分 TypeScript Compilerの略)

このtscは設定によって、出力先フォルダやブラウザのバージョン等色々なJavaScriptに変化させることができます。それの設定ファイルをいじっていきましょう。

$ tsc --init
message TS6071: Successfully created a tsconfig.json file.

これでtsconfig.jsontscの設定ファイルとして生成されました。色々書いてありますが、今回は次のように直します。

{
  "compilerOptions": {
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "outDir": "./javascript/",                        /* Redirect output structure to the directory. */
    "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    "strict": true,                           /* Enable all strict type-checking options. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
  },
  "include": [
    "typescript/*"
  ],
}

今回はわかりやすいように、TypeScriptのファイルをtypescriptに、JavaScriptのファイルをjavascriptに格納していきます。

4. TypeScriptを書いてみる

ディレクトリ構成はこちら。

f:id:syakoo:20190807131651p:plain
ディレクトリ構成

\html\javascript\typescriptは手動で作成します。そして、./typescript/helloWorld.tsに以下のコードを記述

function helloWorld(name: string): void {
    let message = name + ': Hello TypeScript :)'

    console.log(message);
}

helloWorld('Syakoo');

関数や引数に型宣言(アノテーション)をしているのがわかります。最初は違和感があるかもしれないですが、これがないと不安な体になっていくと思います(まだなってないけど)

5. tscを用いてトランスパイル

tscの設定ファイルであるtsconfig.jsonがあるディレクトリに移動して次のコマンドを入力

$ tsc

ちなみに、トランスパイルするファイルを選択したい場合はtscの後にファイルを記述するだけで大丈夫です。

すると、空だったはずの./javascript/に変化が...!!

f:id:syakoo:20190807132723p:plain
トランスパイル結果

./typescript/にあったhelloWorld.tshelloWorld.jsとなって保存されているのがわかります。フォルダー名まで残っているのは、ファイル名が同一だったときの衝突を防いでいると思うし仕方ないと思います。実際にhelloWorld.jsの中身を見てみると...

f:id:syakoo:20190807133108p:plain
helloWorld.js

型宣言がなくなっているのでしっかりjavascriptに変換されているのがわかりますね。これを実行してみましょう。実行するにはnodeのコマンドでターミナル上でjsファイルを実行することができます。(さすがサーバーサイドjs!!!)

$ node javascript/typescript/helloWorld.js
Syakoo: Hello TypeScript :)

ちゃんと出力されました。

6. htmlで動作確認

実際にnode上で動作確認はしたけれど、一応htmlでも動作確認したいと思うのでしていきます。./html/index.htmlに以下のコードを記述します。

<!DOCTYPE html>
<html>
    <head>
        <script src="../javascript/typescript/helloWorld.js"></script>
    </head>
    <body>
        <h1>TypeScript Test</h1>
    </body>
</html>

そして、このファイルをGoogle Chrome等で開くと...

f:id:syakoo:20190807135440p:plain
動作結果

ちゃんとconsole上に表示できましたね。これで終わります。

7. さいごに

TypeScriptいかがだったでしょうか?TypeScriptをここで知った人はおそらく、「なんとなくわかったけれど、JavaScriptで書いた方がよくね?」と思う人が多いと思います。確かに今回のような短いコードだと型宣言もおっくうですし、JavaScriptで書いた方が早いしわかりやすいとおもいます。けれど、ファイルが多くなって、オブジェクト毎にファイルを保管するようになり始めるとTypeScriptのありがたみがすごくわかると思います。

実際にフロントエンドはSPA(Single Page Application)といってページ遷移なしでデータを非同期で拾ってくる方式が多くなっていると思います。それらの軸は紛れもないJavaScriptですので、それのスーパーセットであるTypeScriptを勉強していくことをお勧めします。

Webサービスに関わる予定がない方もIT関係であれば、こういう言語があるってことを頭の片隅にでも置いていただけると幸いです。

計画していたサイトについて

本題

以前まで計画していた、数学のサイトについて今回は断念することにしました。理由は

無料で作れるサービスではない

と感じたからです。 今まで以下の仕様で計画を練っていました。

Firebaseの無料サービス

Node.js(Express.js)

その中で、ユーザー認証を主にした動作確認をしたとき、かなり(2~3秒くらい)時間がかかりました。理由はデータベースと接続の時間だったと考えています。それくらいの時間くらい許せよ~と思う方もいるとは思いますが、一人の動作確認でこれほど時間がかかっていたら複数人で複数の動作を処理していたらとても待てないと思いますし、UXに影響してくると思います。

思い返すと、自分がやろうとしていることが無料で実装出来たらFirebaseの商売にならないですね。流石に有料で組む余裕がないので諦めることにしました。

でも、せっかくFirebaseを触ったので、小さいサービス(API等)は作っていきたいと思いました。