点数
76点
感想
1〜5章は「Next.jsでつくるフルスタックアプリ前編」と全く同じ内容で、補章だけが追加されていた。
補章は「JavaScriptをTypeScriptに移行していく」という内容なので仕方がないことだが、少々分かりづらく退屈な内容だった。
環境構築
最初からTypeSciptを導入する場合
npx create-next-app --ts xxxxxxx
後からTypeScriptに移行する場合 ※書籍内ではこちらの方法
- touch tsconfig.jsonとして以下の内容を貼り付ける。
 https://github.com/mod728/nextjs-book-full-stack-app-typescript/blob/backendts/tsconfig.json
- tsconfig.json内でincludeされているnext-env.d.tsが存在しないので作成する。
 (includeはTypeScriptを適用するファイルを指定するもの)
 これによりReactがグローバルで使えるようになり、CSS Modulesが使えるようになる。
 touch next-env.d.ts
- 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化
- mv utils/schemaModel.js utils/schemaModel.ts
 mongooseの型定義部分に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化
- mv utils/database.js utils/database.ts/
 ※ 型定義が必要な箇所はないため、ファイル名の変更のみ
utils/auth.jsのTypeScript化
- mv utils/auth.js utils/auth.ts
- req, resはNext.jsが用意しているNextApiRequest型, NextApiResponse型を利用する。
- さらに、リクエストにはヘッダにauthorization、ボディにemailがあるのでNextApiRequestを継承した型を定義する。
- ミドルウェアはpagesディレクトリ内の関数コンポーネントを引数として受け取るので、引数はFunction型とする。
- jwt.verufyの戻り値の型はstring | jwt.JwtPayloadであるため、型アサーションを使って変数の型を上書きする。
- NextApiResponseはジェネリックを使ってレスポンスの型を指定する
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の作成
- touch utils/types.ts
 utils/schemaModel.tsのItemDataTypeとUserDataTypeをこちらに移動してexportを付ける。
// 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の修正
- utils/schemaModel.tsにimportを追加。
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); 
  
  
  
  


コメント