Several developers don't use TypeScript when they are starting a project or just trying to implement their new idea. TypeScript could be cumbersome and slow down the development process due to the need to add more code. However, when the project grows larger, it is inevitable that TypeScript can help a lot by catching bug and typing errors. This guide will show you how to migrate your already growing project in JavaScript to TypeScript. Specifically, this post will guide you how to migrate to TypeScript if you use Fastify as your framework.
1. Install Packages
Install these packages by adding --save-dev
option
@types/node
- 'typescript'
ts-node
- 'fastify-tsconfig'
- 'concurrently'
npm i -D @types/node typescript ts-node fastify-tsconfig concurrently
If you want to use a testing library tap
, also add @types/tap
in devDependencies
npm i -D tap @types/tap
2. package.json
Change the script
field of package.json
into these lines
"scripts": {
"start": "npm run build:ts && fastify start -l info dist/app.js",
"build:ts": "tsc",
"watch:ts": "tsc -w",
"dev": "npm run build:ts && concurrently -k -p \"[{name}]\" -n \"TypeScript,App\" -c \"yellow.bold,cyan.bold\" \"npm:watch:ts\" \"npm:dev:start\"",
"dev:start": "fastify start --ignore-watch=.ts$ -w -l info -P dist/app.js"
},
If you want to enable testing using tap
, add this line into scripts
"test": "npm run build:ts && tsc -p test/tsconfig.json && tap --ts \"test/**/*.test.ts\"",
3. tsconfig.json
Create a new tsconfig.json
inside the root directory.
{
"extends": "fastify-tsconfig",
"compilerOptions": {
"outDir": "dist",
"sourceMap": true
},
"include": ["src/**/*.ts"]
}
Note: Modify the include
field to your project needs. In my case, all my app is stored inside a /src
folder.
4. The App Itself
Change all files that ends with
.js
to.ts
.
app.js
or server.js
or index.js
This file is the main entry point of your Node.js application
Before:
module.exports = function (fastify, opts) { ... }
After:
export default function(fastify: FastifyInstance, opts: FastifyServerOptions) { ... }
Plugins
Change require("module")
to import module from "module"
, including fastify-plugin
.
Before (mongodb.js
):
const fp = require('fastify-plugin')
module.exports = fp(async function (fastify, opts) {
fastify.register(require('@fastify/mongodb'))
})
After (mongodb.ts
):
import fp from 'fastify-plugin'
import fastifyMongodb from '@fastify/mongodb'
export default fp(async function (fastify, opts) {
fastify.register(fastifyMongodb)
})
By using import
, TypeScript knows that you will call fastify.mongo
somewhere inside your app. Note that Fastify stated that "declaration merging is not very smart" i.e. if you import
the plugin somewhere but did not call fastify.register
, then TypeScript still assumes that you already registered it.
Furthermore, some plugins have additional rules. Be sure to check their documentation. For example, if you use @fastify/env
to load your .config
file, you need to add this code.
declare module 'fastify' {
interface FastifyInstance {
config: {
field1: string,
field2: string
};
}
}
export default fp(async function (fastify, opts) {
const schema = { ... }; // JSON-schema that match data
const data = { field1: 'Value 1', field2: 'Value 2' };
fastify.register(fastifyEnv, {
schema: schema,
data: data
})
})
Custom Request
You might want to access a specific request.body
or request.query
. To tell TypeScript that a request
has these fields, you need to create a new type that based on FastifyRequest
. Example:
type CustomRequest = FastifyRequest<{
Body: {
username: string
},
Querystring: {
product_id: string
}
}>
function root(fastify: FastifyInstance, request: CustomRequest, reply: FastifyReply) {
const username = request.body.username;
const productId = request.query.product_id;
// ...
}
Further Readings
This guide mainly came from how fastify-cli
generates a new Fastify project with TypeScript in mind. Check this out to read more.
If you have more issues, feel free to comment down below and I will try to help you. Here are other links that might help you.
Top comments (0)