In this tutorial, we will learn how to use Sequelize with TypeScript. Sequelize is an ORM (Object Relational Mapper) for Node.js that provides an easy-to-use API for interacting with databases, while TypeScript is a superset of JavaScript that adds optional static typing, making it easier to write and maintain complex code.

Combining Sequelize with TypeScript can provide several benefits, such as better code completion, enhanced code readability, and improved type safety. Let's get started by setting up our project.


Setting up the Project

First, we need to create a new Node.js project by running the following command in our terminal:

mkdir sequelize-typescript && cd sequelize-typescript
npm init -y

Next, we will install the required dependencies for our project:

npm install --save sequelize sequelize-typescript mysql2
npm install --save-dev @types/sequelize @types/mysql2 typescript ts-node nodemon

Here's a brief explanation of what each of these dependencies does:

  • sequelize: The Sequelize library itself
  • sequelize-typescript: Adds TypeScript support for Sequelize
  • mysql2: A MySQL driver for Node.js
  • @types/sequelize: TypeScript type definitions for Sequelize
  • @types/mysql2: TypeScript type definitions for the mysql2 driver
  • typescript: The TypeScript compiler
  • ts-node: A TypeScript execution environment for Node.js
  • nodemon: A tool that automatically restarts the Node.js application when file changes are detected.

With the dependencies installed, we can now proceed to create the project's directory structure.


Creating the Project's Directory Structure

We will create a directory named src at the root of our project, which will contain the source code for our application. Inside the src directory, we will create two subdirectories: models and config. The models directory will contain our database models, while the config directory will contain our Sequelize configuration file.

Here's the directory structure we will create:

sequelize-typescript/
├── node_modules/
├── src/
│   ├── config/
│   │   └── database.ts
│   ├── models/
│   └── index.ts
├── package.json
├── tsconfig.json
└── nodemon.json


Now let's configure Sequelize to connect to our database.


Configuring Sequelize

In the config directory, create a new file named database.ts. This file will contain the Sequelize configuration.

Here's an example of how to configure Sequelize to connect to a MySQL database:

import { Sequelize } from 'sequelize-typescript';

const sequelize = new Sequelize({
  database: 'my_database',
  dialect: 'mysql',
  username: 'my_username',
  password: 'my_password',
  host: 'localhost',
  port: 3306,
  models: [__dirname + '/../models'],
});

export default sequelize;


In this example, we import the Sequelize library and create a new instance of the Sequelize class. We pass an object to the constructor that contains the connection details for our MySQL database. We also specify the directory where our models will be located.

Now let's create a model to test our configuration.


Creating a Model

In the models directory, create a new file named user.ts. This file will define our User model.

Here's an example of how to define a User model:

import { Model, DataTypes } from 'sequelize';
import sequelize from '../config/database';

class User extends Model {
  public id!: number;
  public name!: string;
  public email!: string;
}

User.init({ id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING(255),
allowNull: false,
},
email: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
},
}, {
sequelize,
tableName: 'users',
});

export default User;
 

In this example, we import the `Model` and `DataTypes` classes from Sequelize, as well as our `sequelize` instance from the `database.ts` file. We define our `User` model as a subclass of the `Model` class, and specify the attributes of the `User` model in the `init` method. We also specify the name of the table in the database that corresponds to our `User` model.

Now let's test our model by adding a new user to the database.


Adding a User to the Database

In the `index.ts` file inside the `src` directory, add the following code:

import User from './models/user';

(async () => {
  await User.sync({ force: true });

  const user = await User.create({
    name: 'John Doe',
    email: 'john.doe@example.com',
  });

  console.log(user.toJSON());
})();

In this code, we import our User model and call the sync method to create the users table in the database. We also create a new user by calling the create method on the User model, and log the user's JSON representation to the console.

Finally, we call this code inside an immediately invoked async function to run it.


Running the Application

To run the application, open a terminal window in the project's root directory and run the following command:

npm run dev

This command will start the application using nodemon, which will automatically restart the application when file changes are detected.

If everything is working correctly, you should see the following output in the console:

Executing (default): DROP TABLE IF EXISTS `users`;
Executing (default): CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER UNSIGNED auto_increment , `name` VARCHAR(255) NOT NULL, `email` VARCHAR(255) UNIQUE NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
{
  "id": 1,
  "name": "John Doe",
  "email": "john.doe@example.com",
  "createdAt": "2023-05-10T16:00:00.000Z",
  "updatedAt": "2023-05-10T16:00:00.000Z"
}

This output indicates that our User model was successfully synchronized with the database, a new users table was created, and a new user was added to the database.


Conclusion

In this tutorial, we learned how to use Sequelize with TypeScript to create a simple Node.js application that interacts with a MySQL database. We set up the project's directory structure, configured Sequelize to connect to the database, defined a User model, and added a new user to the database. Combining Sequelize with TypeScript can make it easier to write and maintain complex code, and provide several benefits such as better code completion, enhanced code readability, and improved type safety.