サイトアイコン 上尾市のWEBプログラマーによるブログ

「Next.jsでつくるフルスタックアプリwith TypeScript 前編」の感想・備忘録1

点数

76点

感想

1〜5章は「Next.jsでつくるフルスタックアプリ前編」と全く同じ内容で、補章だけが追加されていた。

1〜5章はこちらと同じ内容

補章は「JavaScriptをTypeScriptに移行していく」という内容なので仕方がないことだが、少々分かりづらく退屈な内容だった。

環境構築

最初からTypeSciptを導入する場合

npx create-next-app --ts xxxxxxx

後からTypeScriptに移行する場合 ※書籍内ではこちらの方法

  1. touch tsconfig.jsonとして以下の内容を貼り付ける。
    https://github.com/mod728/nextjs-book-full-stack-app-typescript/blob/backendts/tsconfig.json
  2. tsconfig.json内でincludeされているnext-env.d.tsが存在しないので作成する。
    (includeはTypeScriptを適用するファイルを指定するもの)
    これによりReactがグローバルで使えるようになり、CSS Modulesが使えるようになる。
    touch next-env.d.ts
  3. TypeScriptおよびタイプ情報のパッケージをインストール
    Next.jsのTypeScript化には以下のパッケージが必要。
    ※ nextとmongooseはタイプ情報が含まれているので@typeは不要
    npm install --save-dev typescript @types/react @types/react-dom @types/node
    書籍内ではjsonwebtokenも使っているので以下のパッケージも必要。
    npm install --save-dev @types/jsonwebtoken
/// <reference types="next" />
/// <reference types="next/image-types/global" />

utilsディレクトリのTypeScript化

utils/schemaModel.jsのTypeScript化

import mongoose from 'mongoose'

const Schema = mongoose.Schema;
interface ItemDataType {
  title: string,
  image: string,
  price: string,
  description: string,
  email: string
}
// 追加
interface UserDataType {
  name: string,
  email: string,
  password: string,
}
// <ItemDataType>を追加
const ItemSchema = new Schema<ItemDataType>({
  title: String,
  image: String,
  price: String,
  description: String,
  email: String
});
// <UserDataType>を追加
const UserSchema = new Schema<UserDataType>({
  name: {
    type: String,
    required: true,
    unique: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
    required: true
  },
});
// <ItemDataType>を追加
export const ItemModel = mongoose.models.Item || mongoose.model<ItemDataType>("Item", ItemSchema);
// <UserDataType>を追加
export const UserModel = mongoose.models.User || mongoose.model<UserDataType>("User", UserSchema);

utils/database.jsのTypeScript化

utils/auth.jsのTypeScript化

import type {NextApiRequest, NextApiResponse} from 'next'
import jwt from 'jsonwebtoken'
interface DecodedType  {
  email: string
}
interface ExtendedNextApiRequestAuth extends NextApiRequest {
  headers: {
    authorization: string
  },
  body: {
    email: string
  }
}
interface ResMsgType {
  msg: string
}
const middleware = (handler: Function) => {
  return async (req: ExtendedNextApiRequestAuth, res: NextApiResponse<ResMsgType>) => {
    if (req.method === 'GET') {
      return handler(req, res);
    }
    // JWTではトークンを「Bearer xxxxxxxxxx」とするのが慣習なのでスペースで分割する
    const token = req.headers.authorization.split(' ')[1];
    if (!token) {
      return res.status(401).json({ msg: 'トークンがありません。' })
    }
    try {
      const decoded = jwt.verify(token, 'hogehogehoge');
      req.body.email = (decoded as DecodedType).email;
      return handler(req, res);
    } catch (err) {
      return res.status(401).json({ msg: 'トークンが正しくありません。' })
    }
  };
};
export default middleware;

共通型定義の切り出し

utils/types.tsの作成

// exportを追加
export interface ItemDataType {
  title: string,
  image: string,
  price: string,
  description: string,
  email: string
}
// exportを追加
export interface UserDataType {
  name: string,
  email: string,
  password: string,
}

utils/schemaModel.tsの修正

import mongoose from 'mongoose'
// 追加
import {ItemDataType, UserDataType} from "./types";

const Schema = mongoose.Schema;
const ItemSchema = new Schema<ItemDataType>({
  title: String,
  image: String,
  price: String,
  description: String,
  email: String
});
const UserSchema = new Schema<UserDataType>({
  name: {
    type: String,
    required: true,
    unique: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
    required: true
  },
});
export const ItemModel = mongoose.models.Item || mongoose.model<ItemDataType>("Item", ItemSchema);
export const UserModel = mongoose.models.User || mongoose.model<UserDataType>("User", UserSchema);
モバイルバージョンを終了