LoginSignup
18
18

More than 1 year has passed since last update.

TypeScript でWebアプリ開発

Last updated at Posted at 2023-04-09

はじめに

TypeScript はフロントエンド開発とバックエンド開発の両方で利用することができます。
この記事では、フロントエンドとバックエンドの両方で TypeScript を利用したToDoリストのWebアプリを開発します。

開発環境

  • Windows11
  • VSCode
  • TypeScript 4.9.5
  • React 18.2.0
  • React Router 6.10.0
  • Vite 4.1.0

プロジェクトフォルダの作成

まずWebアプリ用に todo-app というフォルダを作成し、その中に frontendbackend というフォルダを作成しました。
image.png

バックエンド開発

まずはバックエンドを開発してきます。

package.jsonの作成

Node.jsでのアプリ開発を行うため、以下のコマンドで package.json を作成します。

yarn init -y

以下の package.json ファイルが作成されます。

package.json
{
  "name": "backend",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT"
}

tsconfig.jsonの作成

TypeScriptを利用できるようにするため、以下2つのパッケージをインストールします。

  • typescript
  • @types/node
yarn add -D typescript @types/node

yarn.locknode_modules が新たに作成され、package.json にも以下の値が追加されます。

package.json
"devDependencies": {
  "@types/node": "^18.15.5",
  "typescript": "^5.0.2"
}

次に tsconfig.json を作成するため、以下のコマンドを実行します。

yarn tsc --init

作成された tsconfig.json 内の target"esnext" に変更します。

Expressの導入

Node.jsのフレームワークであるExpressを導入します。
以下のコマンドでExpressをインストールします。

yarn add express

package.json に以下の値が追加されます。

package.json
"dependencies": {
  "express": "^4.18.2"
}

TypeScriptを使うため、以下のコマンドも実行します。

yarn add -D @types/express

package.json"devDependencies""@types/express": "^4.17.17" が追加されます。

次にバックエンド開発のメインのファイルとなる server.ts というファイルを backend フォルダ直下に作成します。そして、package.json"main""server.js" に書き換えます。
server.ts では、Express を利用できるように以下のコードを書きます。

backend/server.ts
import express, { Express } from "express";

const app: Express = express();

Expressの起動

実際にExpressを起動して、動作確認をしてみます。
確認用にログを出力するコードを書きます。

backend/server.ts
import express, { Express, Request, Response } from "express";

const app: Express = express();
const port = 3001;

app.get("/", (req: Request, res: Response) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`listening on port ${port}`);
});

次にTypeScriptをNode.jsで実行するために ts-node をインストールします。

yarn add -D ts-node

そして、ローカルサーバーを起動します。

yarn ts-node server.ts

ローカルサーバーを起動することができ、ログも表示されました。
image.png
また、ブラウザで http://localhost:3001 にアクセスすると、「Hello World!」と表示されます。
image.png

ts-node をインストールせずにローカルサーバーを起動すると、エラーが出てしまいます。

node server.ts

image.png

CROS設定

次に CORS1 対応のため、CORS というミドルウェアをインストールします。TypeScript対応のため、@types/cors も一緒にインストールします。

yarn add cors @types/cors

次にCORSをインポートして全てのAPIをCORS許可します。

backend/server.ts
import express, { Express, Request, Response } from "express";
import cors from "cors";

const app: Express = express();
const port = 3001;

app.use(cors());

ToDoリスト取得機能の実装

ToDoリストの取得機能を実装します。

まずはToDoの型を定義します。

types/index.ts
export type Todo = { id: number; title: string; completed: boolean };

次に "/todo-list" にアクセスすると、ToDoリストを返すようにします。

backend/server.ts
import express, { Express, Request, Response } from "express";
import { Todo } from "../types";
import cors from "cors";

const app: Express = express();
const port = 3001;

app.use(cors());

const sampleData = [
  { id: 1, title: "牛乳を買う", completed: false },
  { id: 2, title: "洗濯をする", completed: true },
  { id: 3, title: "請求書を支払う", completed: false },
];

let todoList: Todo[] = sampleData;

app.get("/", (req: Request, res: Response) => {
  res.send("Hello World!");
});

app.get("/todo-list", (req: Request, res: Response) => {
  res.json(todoList);
});

app.listen(port, () => {
  console.log(`listening on port ${port}`);
});

動作確認をします。
image.png

これでバックエンドの開発は完了です!

フロントエンド開発

次はフロントエンドを開発していきます。

Reactプロジェクトの作成

以下のコマンドでプロジェクトを作成します。

yarn create vite . --template react-ts

以下のコマンドを実行すると、ローカルサーバーが起動します。

yarn
yarn dev

ローカルサーバーが起動したことを確認できました。
image.png

vite.config.ts でポートの指定やローカルサーバー起動時にブラウザを自動起動する設定を追加することができます。

vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
    open: true,
  },
});

ルーティング作成

次にルーティングを作成します。
今回は React Router を利用します。
まずは、以下のコマンドでインストールします。

yarn add react-router-dom

次にフロントエンドのコードにルーターを追加します。

frontend/src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const router = createBrowserRouter([
  { path: "/", element: <div>ToDoリスト</div> },
]);

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

動作確認をします。ルートにアクセスすると、「ToDoリスト」と表示されることが確認できました。
image.png

ToDoリストコンポーネント作成

次は <div>ToDoリスト</div> と書いていた箇所をコンポーネント化します。

frontend/src/routes/Home.tsx
import { FC } from "react";

export const Home: FC = () => {
  return (
    <div>
      <h1>ToDoリスト</h1>
    </div>
  );
};
frontend/src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { Home } from "./routes/Home";

const router = createBrowserRouter([{ path: "/", element: <Home /> }]);

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

バックエンドへアクセス

次はいよいよ先に作成したバックエンド(APIサーバー)へアクセスする機能を実装します。今回は Fetch APISWR を利用して実装します。

まずは、SWR をインストールします。

yarn add swr

次に fetch をSWRで利用できるようにするため、fetch をラップした fetcher 関数を作成します。

frontend/src/api/index.ts
export const fetcher = async (path: string) => {
  try {
    const res = await fetch("http://localhost:3001" + path);
    return res.json();
  } catch (error) {
    alert(error);
  }
};

次にSWRを利用して、ToDoリスト取得できるようにします。

frontend/src/api/index.ts
export const useTodoList = () => useSWR<Todo[]>("/todo-list", fetcher);

そして、Home コンポーネント内で useTodoList をインポートしてAPIを呼び出し、その結果をレンダリングします。

frontend/src/routes/Home.tsx
import { FC } from "react";
import { useTodoList } from "../api";

export const Home: FC = () => {
  const { data: todoList, error, isLoading } = useTodoList();

  if (error) return <div>failed to load</div>;
  if (isLoading) return <div>loading...</div>;

  return (
    <div>
      <h1>ToDoリスト</h1>
      <ul>
        {todoList?.map((todo) => (
          <li key={todo.id}>
            <input
              type="checkbox"
              id={String(todo.id)}
              checked={todo.completed}
            />
            <label htmlFor={String(todo.id)}>{todo.title}</label>
          </li>
        ))}
      </ul>
    </div>
  );
};

動作確認をします。ToDoリストが取得できました!
image.png

最後に

今回はフロントエンドとバックエンドの両方でTypeScriptを利用したToDoリストのWebアプリを開発しました。両方とも同じ言語だと実装しやすいですね。

参考

  1. CORS の説明は、こちらの記事がとてもわかりやすかったです。

18
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
18