Introduction: Why TypeScript and Databases Are a Perfect Pair
Modern web development is unthinkable without working with databases. TypeScript, as a strictly typed superset of JavaScript, offers developers a powerful tool for creating reliable and scalable applications. In this article, we will practically explore how to connect and use two of the most popular databases — the relational PostgreSQL and the document-oriented MongoDB — in the TypeScript ecosystem.
You will learn how to configure an ORM/ODM, write typed models, and perform basic CRUD operations. The material is intended for developers already familiar with the basics of TypeScript and Node.js.
1. Project Setup and Dependency Installation
Before writing code, let's create a new project and install the necessary packages. For working with PostgreSQL, we will use TypeORM — one of the most popular ORMs for TypeScript. For MongoDB — Mongoose.
Project Initialization
mkdir typescript-db-practicecd typescript-db-practicenpm init -ynpm install typescript ts-node @types/node --save-devnpx tsc --initInstalling Dependencies for PostgreSQL
npm install typeorm reflect-metadata pgnpm install @types/node --save-devInstalling Dependencies for MongoDB
npm install mongoosenpm install @types/mongoose --save-devAfter installation, in the tsconfig.json file, be sure to enable the options "experimentalDecorators": true and "emitDecoratorMetadata": true — they are necessary for TypeORM to work.
2. Working with PostgreSQL via TypeORM
TypeORM supports both Active Record and Data Mapper patterns. We will look at Data Mapper, as it provides more flexibility and aligns better with clean architecture.
Creating an Entity
Let's create a user model. Each entity is a class decorated with special annotations.
// src/entities/User.tsimport { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';
@Entity()export class User { @PrimaryGeneratedColumn() id: number;
@Column({ length: 100 }) name: string;
@Column({ unique: true }) email: string;
@Column({ select: false }) password: string;
@CreateDateColumn() createdAt: Date;}Configuring the Connection and Repository
Let's create a file for initializing the database and a repository for working with users.
// src/data-source.tsimport "reflect-metadata";import { DataSource } from "typeorm";import { User } from "./entities/User";
export const AppDataSource = new DataSource({ type: "postgres", host: "localhost", port: 5432, username: "postgres", password: "password", database: "test_db", synchronize: true, // Auto-create tables (for development only!) logging: false, entities: [User], migrations: [], subscribers: [],});// src/repositories/userRepository.tsimport { AppDataSource } from "../data-source";import { User } from "../entities/User";
export const userRepository = AppDataSource.getRepository(User);CRUD Operations in Practice
// src/index.tsimport { AppDataSource } from "./data-source";import { userRepository } from "./repositories/userRepository";
async function main() { await AppDataSource.initialize(); console.log("PostgreSQL connected!");
// CREATE const newUser = userRepository.create({ name: "Ivan Petrov", email: "ivan@example.com", password: "hashed_password" }); await userRepository.save(newUser); console.log("User created:", newUser);
// READ const us