TypeScriptで記述したNext.jsをExpressのミドルウェアにしたい
こんにちは。現在「実践TypeScript 吉井健文著」という書籍でTypeScriptを学習しているものです。
その書籍中の10章10-3-3においてまず下記のsrc/server/index.tsでNext.jsをインポートしたserverのエントリーポイントでnextAppインスタンスを生成する。この場合はnextAppインスタンス生成時の設定で、ベースディレクトリをsrc/clientに指定する。
次にExpressがRedis Storeに接続するミドルウェアを下記(src/server/session.ts)のように設定をする。
ここまでで、Next.jsアプリケーションがマウントされたExpressサーバーを構築することができました。yarn devでサーバーを起動してアプリケーションが動いているのを確認する。しかし以下のようなエラーがでた。
発生している問題・エラーメッセージ
yamashitajunichinoMacBook-Pro:ts-nextjs-express-master yamajon$ yarn dev yarn run v1.22.4 warning package.json: "dependencies" has dependency "@types/next" with range "^8.0.3" that collides with a dependency in "devDependencies" of the same name with version "8.0.3" $ ts-node src/server/index.ts /Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/ts-node/src/index.ts:226 return new TSError(diagnosticText, diagnosticCodes) ^ TSError: ⨯ Unable to compile TypeScript: src/server/index.ts:13:26 - error TS2339: Property 'getRequestHandler' does not exist on type 'DevServer'. 13 const handle = nextApp.getRequestHandler() ~~~~~~~~~~~~~~~~~ src/server/index.ts:14:17 - error TS2339: Property 'prepare' does not exist on type 'DevServer'. 14 await nextApp.prepare() ~~~~~~~ src/server/index.ts:24:42 - error TS2345: Argument of type '(err: Errback) => void' is not assignable to parameter of type '() => void'. 24 app.listen(ENV.APP_PORT, ENV.APP_HOST, (err: Express.Errback) => { ~~~~~~~~~~~~~~~~~~~~~~~~~~~ at createTSError (/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/ts-node/src/index.ts:226:12) at getOutput (/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/ts-node/src/index.ts:335:40) at Object.compile (/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/ts-node/src/index.ts:368:11) at Module.m._compile (/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/ts-node/src/index.ts:414:43) at Module._extensions..js (internal/modules/cjs/loader.js:1272:10) at Object.require.extensions.<computed> [as .ts] (/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/ts-node/src/index.ts:417:12) at Module.load (internal/modules/cjs/loader.js:1100:32) at Function.Module._load (internal/modules/cjs/loader.js:962:14) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12) at Object.<anonymous> (/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/ts-node/src/bin.ts:151:12) error Command failed with exit code 1.
該当のソースコード
src/server/index.tsにおいてvscodeでコメントアウトのようなエラーがでていた
src/server/index.ts
typescript
1import Express from 'express' 2import next from 'next' 3import session from './session' 4import * as ENV from '../constants' 5// ______________________________________________________ 6// 7const dev = process.env.NODE_ENV !== 'production' 8 // ______________________________________________________ 9 // 10;(async () => { 11 const app = Express() 12 const nextApp = next({ dev, dir: './src/client' }) 13 const handle = nextApp.getRequestHandler() 14 //プロパティ 'getRequestHandler' は型 'DevServer' に存在しません。 15 await nextApp.prepare() 16 //プロパティ 'prepare' は型 'DevServer' に存在しません。 17 18 session(app) 19 20 app.use((req, res) => { 21 22 handle(req, res) 23 }) 24 app.listen(ENV.APP_PORT, ENV.APP_HOST, (err: Express.Errback) => { 25 //この呼び出しに一致するオーバーロードはありません。 26 // 6 中 1 のオーバーロード, '(port: number, hostname: string, backlog: number, callback?: (() => void) | undefined): Server' により、次のエラーが発生しました。 27 // 型 '(err: Express.Errback) => void' の引数を型 'number' のパラメーターに割り当てることはできません。 28 // 6 中 2 のオーバーロード, '(port: number, hostname: string, callback?: (() => void) | undefined): Server' により、次のエラーが発生しました。 29 // 型 '(err: Express.Errback) => void' の引数を型 '() => void' のパラメーターに割り当てることはできません。ts(2769) 30 if (err) throw err 31 console.log(`Running on http://${ENV.APP_HOST}:${ENV.APP_PORT}`) 32 }) 33})() 34
同様にsrc/server/session.tsのconnectRedis(session)においてもvscode上でエラーが出ていた。
src/server/session.ts
typescript
1import Express from 'express' 2import session from 'express-session' 3import connectRedis from 'connect-redis' 4import { REDIS_HOST, REDIS_PORT } from '../constants' 5 6export default (app: Express.Application) => { 7 const RedisStore = connectRedis(session) 8 // 型 'typeof session' の引数を型 '(options?: SessionOptions | undefined) => RequestHandler<ParamsDictionary, any, any, ParsedQs>' のパラメーターに割り当てることはできません。 9 // パラメーター 'options' および 'options' は型に互換性がありません。 10 // 型 'import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/connect-redis/node_modules/@types/express-session/index").SessionOptions | undefined' を型 'import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/express-session/index").SessionOptions | undefined' に割り当てることはできません。 11 // 型 'import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/connect-redis/node_modules/@types/express-session/index").SessionOptions' を型 'import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/express-session/index").SessionOptions' に割り当てることはできません。 12 // プロパティ 'store' の型に互換性がありません。 13 // 型 'import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/connect-redis/node_modules/@types/express-session/index").Store | import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/connect-redis/node_modules/@types/express-session/index").MemoryStore | und...' を型 'import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/express-session/index").Store | import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/express-session/index").MemoryStore | undefined' に割り当てることはできません。 14 // 型 'MemoryStore' を型 'Store | MemoryStore | undefined' に割り当てることはできません。 15 // 型 'import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/connect-redis/node_modules/@types/express-session/index").MemoryStore' を型 'import("/Users/yamajon/Desktop/JS_practice/ts-nextjs-express-master/node_modules/@types/express-session/index").MemoryStore' に割り当てることはできません。 16 // プロパティ 'all' の型に互換性がありません。 17 // 型 '((callback: (err: any, obj?: SessionData[] | { [sid: string]: SessionData; } | null | undefined) => void) => void) | undefined' を型 '(callback: (err: any, obj?: { [sid: string]: SessionData; } | null | undefined) => void) => void' に割り当てることはできません。 18 //型 'undefined' を型 '(callback: (err: any, obj?: { [sid: string]: SessionData; } | null | undefined) => void) => void' に割り当てることはできません。ts(2345) 19 const option = { 20 store: new RedisStore({ 21 host: REDIS_HOST, 22 port: REDIS_PORT 23 24 }), 25 secret: 'keyboard cat', 26 resave: false 27 } 28 app.use(session(option)) 29}
constantsは以下の通り
src/constants.ts
typescript
1export const APP_HOST = 'localhost' 2export const REDIS_HOST = 'localhost' 3export const APP_PORT = 3000 4export const REDIS_PORT = 6379
npm installで使用したpackage.jsonは以下のものです
json
1{ 2 "name": "ts-nextjs-express", 3 "version": "1.0.0", 4 "author": "takepepe", 5 "private": true, 6 "scripts": { 7 "dev": "ts-node src/server/index.ts", 8 "redis": "ts-node src/redis/index.ts", 9 "prettier": "prettier \"src/**/*.ts*\" --write" 10 }, 11 "dependencies": { 12 "@types/connect-redis": "0.0.9", 13 "@types/next": "^8.0.3", 14 "axios": "^0.20.0", 15 "body-parser": "1.18.3", 16 "connect-redis": "3.4.1", 17 "cookie-parser": "1.4.4", 18 "express": "4.16.4", 19 "express-session": "1.16.0", 20 "next": "^8.0.3", 21 "react": "16.8.6", 22 "react-dom": "16.8.6", 23 "redis-server": "1.2.2", 24 "styled-components": "4.2.0" 25 }, 26 "devDependencies": { 27 "@types/axios": "0.14.0", 28 "@types/body-parser": "1.19.0", 29 "@types/cookie-parser": "1.4.1", 30 "@types/express": "4.16.1", 31 "@types/express-session": "1.15.12", 32 "@types/node": "11.13.4", 33 "@types/react": "16.8.13", 34 "@types/next": "8.0.3", 35 "@types/react-dom": "16.8.3", 36 "@types/styled-components": "4.1.14", 37 "@zeit/next-typescript": "1.1.1", 38 "prettier": "1.16.4", 39 "ts-node": "8.0.3", 40 "typescript": "3.4.3", 41 "webpack": "4.29.6", 42 "webpack-cli": "^3.3.12", 43 "webpack-node-externals": "1.7.2" 44 }, 45 "prettier": { 46 "semi": false, 47 "singleQuote": true 48 } 49}
プロジェクト構成は以下の通りです。
|_package.json
|_src
| |____redis
| | |_index.ts
| |____server
| | |_index.ts
| | |_session.ts
| |
| |_constant.ts
|
|_node_modeles
| |
| |_express
| |_express-session
| |_connect-redis
| |_next
|
|_next.config.js
|_tsconfig.json
|_yarn.lock
試したこと
まずプロパティ 'getRequestHandler' 、'prepare'は型 'DevServer' に存在しないことを確認してみた。node_module/@types/next/index.d.tsにDevServerは存在したが確かにgetRequestHandler,prepareは存在していなかった。
書籍にはこのコードで問題なく起動すると書いてあったので、自分と違うところがあるとすれば、書籍が書かれた当時の@types/nextのversionと自分が使っている@types/nextのversionが違うのではないかという予測をたて、自分が使っているversionを開発に使用しているディレクトリ上でnpm view @types/next versionで確かめてみたところ、最新バージョン9.0.0が使用されており、なぜかじぶんがpackage.jsonで指定したversion8.3.0が使用されていなかった。
そこでnpm install @types/next@8.0.3でversionを8.0.3にダウングレードさせようとしたが変更できなかった。変更できない理由はそのディレクトリのみversionを引き下げることができないことと思われ、グローバルに変更する必要がありそうなのだが、他のアプリでは最新バージョンのnextを使用しているのでなるべくグローバルに変更したくはない。
よろしければ、どこをどのように修正すればよいと考えられるのか、ご教授いただけると幸いです。もしvesionが問題なのであればグローバルにversionを変更せず、限られたディレクトリ内で低いversionのmoduluを使用する方法もよろしけば教えてください。
###補足情報
環境はmacでエディタはVScodeを使用しています、
ソースコードは著者の方がGitHubで公開しているものを使わせてもらいました
https://github.com/takefumi-yoshii/ts-nextjs-express
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/09/22 06:21