From my weird learning journey, I am logging this article where I wanted to explore something basic. I have always written Node.js with javascript and with Express mostly. So, today, I am trying to write or structure a basic node and express app with typescript. Just a simple and small setup to log, how to setup Node.js with typescript.
NOTE: Now, in Node v25, typescript is included by default and we do not need to use other packages
Some prerequisites of what my system is currently using. So, I use node version manager (nvm) for managing node versions. And currently, I am using Node v22.14.0. Also, I am not using npm for my projects as of now. So, we will be continuing with pnpm. I have used yarn for some projects, but after using it for certain projects, I realised maintaing it is a little cumbersome for me (not for others). There is a classic and newer version of yarn, and migrating it might create some issues for me. And I am writing this after few years of not using yarn. So, people can use it, but I am refraining by my personal choice. I got to know very good things about pnpm, so thought of trying it to see, what it actually does. One of the things I heard was that it is out of Node.js, like npm is inside or tied to Node.js, but pnpm is not tied to it. And I was also listening to one podcast, where the developer was trying to convey the issue where the dependency chain for multiple libraries can use different node versions without affecting the other libraries. And pnpm creator actually working on that to solve it. Thats really intersting, so thats a green flag for me as well.
Setup
- Create a directory for the app
mkdir node-typescript && cd node-typescript
- Initialize app or create package.json
pnpm init- This is similar to
npm init -y
- This is similar to
- Install dev dependencies for typescript
pnpm add -D typescript @types/node tsx
- Create tsconfig.json for configuring typescript
pnpm exec tsc --init
- Install dependecies
pnpm add express @types/express
My Configurations
{ "name": "node-typescript", "version": "1.0.0", "description": "", "main": "dist/app.js", "type": "module", "scripts": { "build": "tsc", "start": "node dist/app.js", "dev": "tsx watch src/app.ts" }, "keywords": [], "author": "", "license": "ISC", "packageManager": "pnpm@10.21.0", "devDependencies": { "@types/node": "^25.5.0", "tsx": "^4.21.0", "typescript": "^6.0.2" }, "dependencies": { "@types/express": "^5.0.6", "express": "^5.2.1" }}
The above code is for package.json
{ // Visit https://aka.ms/tsconfig to read more about this file "compilerOptions": { // File Layout "rootDir": "./src", "outDir": "./dist", // Environment Settings // See also https://aka.ms/tsconfig/module "module": "nodenext", "target": "esnext", "types": [], // For nodejs: // "lib": ["esnext"], // "types": ["node"], // and npm install -D @types/node // Other Outputs "sourceMap": true, "declaration": true, "declarationMap": true, // Stricter Typechecking Options "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, // Style Options // "noImplicitReturns": true, // "noImplicitOverride": true, // "noUnusedLocals": true, // "noUnusedParameters": true, // "noFallthroughCasesInSwitch": true, // "noPropertyAccessFromIndexSignature": true, // Recommended Options "strict": true, // "jsx": "react-jsx", "verbatimModuleSyntax": true, "isolatedModules": true, "noUncheckedSideEffectImports": true, "moduleDetection": "force", "skipLibCheck": true, }, "include": ["src/**/*"], "exclude": ["node_modules"]}
The above code is for tsconfig.json. All of them were generated by the command that I mentioned earlier. I have only added the last 2 key values: “include” and “exclude“. These can be changed according to the requirements.
app.ts file
import express, {type Express, type Request, type Response} from 'express'import { testMiddleware } from './middlewares/addTime.middleware.js'const app: Express = express()const PORT: number = 3001app.use(express.json())app.use(testMiddleware)interface UserData { name: string email: string}app.post('/save-data', (req: Request, res: Response) => { const {name, email}: UserData = req.body res.status(200).json({ data: {name, email}, msg: 'Data saved' })})app.get('/', (req: Request, res: Response) => { res.status(200).json({msg: 'Welcome'})})app.listen(PORT, () => { console.log('Server started on PORT: ', PORT)})
Custom Middleware
import type { NextFunction, Request, Response } from "express";interface CustomRequest extends Request { startTime?: number}export const testMiddleware = (req: CustomRequest, res: Response, next: NextFunction) => { req.startTime = Date.now() next()}
This is a simple setup for express app with typescript. We do not need any nodemon here as “tsx watch” does the work as you all can see it inside scripts in package.json
Leave a comment