TypeScript에서 Sequelize 사용시 알아둘 것

Sequelize는 런타임 property 할당에 크게 의존합니다. 따라서 TypeScript에서 바로 사용하기는 어렵습니다. 모델에서 이러한 속성들을 사용하려면 상당한 양의 수동 설정이 필요합니다.

모델간 관계 설정 및 예시

Sequelize를 사용하면 자주 아래의 예시와 같이 관계를 지정해줄 필요가 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export const associate = (db: dbType) => {
User.hasMany(db.Article, { foreignKey: "authorId" });
User.hasMany(db.Comment, { foreignKey: "writterId" });
User.belongsToMany(db.User, {
foreignKey: "followingId",
as: "followers",
through: "follow",
});

User.belongsToMany(db.User, {
foreignKey: "followerId",
as: "followings",
through: "follow",
});
};

이 코드는 UserArticle, Comment가 1:N 관계를 가지고 팔로우 기능을 위해 User의 N:M관계를 지정해줍니다.

TypeScript의 문제점

이렇게 관계를 지정해주면 런타임에 관계에 상응하는 여러 메서드들이 생성됩니다. 따라서 TypeScript 를 이용하지 않는다면 별도의 설정없이 다양한 메서드들을 바로 사용할 수 있습니다.

1
2
followingUser.addFollower(followerUser);
followingUser.getFollowers();

하지만 TypeScript를 이용하는 경우라면, User 클래스는 addFollowergetFollowers 등과 같은 런타임에 제공되는 메서드들을 가지고 있지 않습니다. 이러한 이유들 때문에 타입스크립트에서 사용하려면 아래와 같은 다소 번거로운 작업을 해주어야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
class User extends Model {
public readonly userId!: number;
public userName!: string;
public email!: string;
public password!: string;

public readonly createdAt!: Date;
public readonly updatedAt!: Date;

public addFollower!: BelongsToManyAddAssociationMixin<User, number>;
public getFollowers!: BelongsToManyGetAssociationsMixin<User>;
}

다음은 sequelize 문서에 소개된 자주 사용하는 메서드들의 타입입니다.

1
2
3
4
5
6
public getProjects!: HasManyGetAssociationsMixin<Project>; // Note the null assertions!
public addProject!: HasManyAddAssociationMixin<Project, number>;
public hasProject!: HasManyHasAssociationMixin<Project, number>;
public countProjects!: HasManyCountAssociationsMixin;
public createProject!: HasManyCreateAssociationMixin<Project>;

모든 메서드들에 대해 이렇게 수작업으로 추가를 해주어야하는 것은 아닙니다. 사용하려는 메서드들만 classmember로 추가해주고 타입을 지정해주시면 됩니다.

여기서 사용한 메서드의 타입이외에 수많은 메서들이 있기 때문에 이글에서 모든 메서드들과 타입들을 모두 소개하지는 않습니다. 이에 대한 추가 정보는 여기에서 확인하실 수 있습니다.