フロント、サーバーともにTypeScriptのWEBアプリケーションにおいて、 NestJS側のEntityやDTO、GraphQLの型をNuxt3側で使えると非常に便利だったのでメモ。
システム全体像にとしてはこの記事参照 uyamazak.hatenablog.com
いろいろ前提
レポジトリはNestJS、Nuxt3は同一で下記のようなディレクトリとします
. ├── types # 共有する型定義置き場 ├── front # Nuxt3のディレクトリ └── server # NestJSのディレクトリ
Nuxt3のバージョンは
"nuxt": "3.0.0-rc.8",
NestJSのバージョンは ここらへん
"@nestjs/apollo": "^10.0.16", "@nestjs/common": "8.0.9", "@nestjs/config": "2.1.0", "@nestjs/core": "8.4.7", "@nestjs/graphql": "10.0.16", "@nestjs/platform-express": "8.4.7", "@nestjs/typeorm": "^8.1.4",
Entity、DTOなど型定義の共有
編集時などよくEntityそのままの値を返すことがあり、Nuxt側のfetchやuseAsyncDataなどに指定できると便利です。
POST、PUTなどのリクエスト時はDTOの型が使えると補完や型チェックができて非常に便利です。
そもそもDTOはなんぞやって場合は下記参照。 NestJS の DTO と Validation の基本 - 型定義とデコレータで安全にデータを受け付ける - Qiita https://docs.nestjs.com/openapi/types-and-parameters#types-and-parameters
出力専用のtsconfingを用意します
server/tsconfig.shared.json
{ "extends": "./tsconfig.json", "include": [ "./src/dto", "./src/entity", "./src/types.ts", "./src/param", "./src/class-validator-jp.ts" ], "compilerOptions": { "outDir": "../types" } }
メインのやつをextendsしつつ、includeで必要なところだけを指定、outDirで上記の出力先ディレクトリを指定します。
毎回手打ちは面倒なので出力コマンドを server/package.jsonに用意しておきます。
"scripts": { "export:types": "rimraf ../types && tsc -P tsconfig.shared.json --emitDeclarationOnly", },
古いゴミが残らない用に書き出し前にrimrafを使って削除を行っています(NestJSのデフォルトprebuildで使ってたので流用) npm run のスクリプトの中でディレクトリの削除を行う (rimraf) - まくまくNode.jsノート
先程用意した出力用tsconfigを指定し、
型定義だけでいいので
--emitDeclarationOnly
を指定します。 これを指定しないと値も出力されるわけですが、それすなわち使用するfront側でもNestJSやその他サーバー側ライブラリのインストールが必要になってしまうので現実的ではありません。
yarnを使っているのでserverディレクトリで
yarn export:types
で出力されるようになります
index.tsも自動生成する
ファイル数が増えてくると、import時に全部指定するのが面倒なのでディレクトリごとにindex.tsがあると便利です。
自動生成してくれる下記ライブラリをインストールして使っています。
yarn add -D create-ts-index
して package.jsonのscriptsに下記のようなコマンドを追加して使っています。 全フォルダにはいらないので、ファイル数が多い必要な場所だけ指定しています。
"cti": "cti create src/dto src/entity -b -s=1 -i=spec.ts",
これで
import { FugaEntiry } from '~/entity/fuga-entity.entity'
のようなfromを
import { FugaEntiry } from '~/entity/'
に省略できるようになります。
Entityの型とレスポンスの型が違う場合
TypeORMでLazy Relationsを使っているとEntityのプロパティの型はそのままPromiseになってしまいますが、 レスポンスとして返す場合はJSONですのでもちろん解決した値を返すと思います。
typeorm/eager-and-lazy-relations.md at master · typeorm/typeorm · GitHub
その場合、あまりきれいではありませんが、上書きして新しい型を作って使うようにしています。 今Nuxt3側で出力してるけど、よく考えるとサーバー側で出力した方が変更しやすくていいかもしれない。
import { HogeEntity, LazyItem } from '~/../types/entity' export interface HogeEntityResponse extends Omit<HogeEntity, 'lazyItems'> { lazyItems: LazyItem[] // 元は Promise<LazyItem[]> }
GraphQLの型を出力する
こちらを参考にCode firstとして使っています。
https://docs.nestjs.com/graphql/quick-start
GraphQLの型を書き出してくれるこいつをインストールします @graphql-codegen/cli - npm
yarn add -D @graphql-codegen/cli
設定ファイルを追加します
server/codegen.yml
schema: ./src/schema.graphql generates: ../types/graphql-types.ts: plugins: - typescript
出力先 (../types/graphql-types.ts) とpluginsでtypescriptを指定するだけで使えました。
これもpackage.jsonのscriptsに追加
"graphql-codegen": "graphql-codegen",
上記の型定義とGraphQLの型定義は同時にやってくれたほうがいいので、つなげて実行してしまっています
"export:types": "graphql-codegen && rimraf ../@shared/@types/server && tsc -P tsconfig.shared.json --emitDeclarationOnly",