콘텐츠로 이동

TypeScript SOLID 법칙

Typescript로 보는 SOLID. BE 직방 부동산팀에서 근무 중인 Oscar 입니다. 저번 포스트에서는… | by 김성준 | 직방 기술 블로그 | Nov, 2022 | Medium

코드 리팩토링, IF문을 제거하자 (전략패턴). 레거시 코드를 리팩토링하며 얻은 경험을 공유합니다. 스프링부트환경에서… | by 배성균 | 직방 기술 블로그 | Medium

Type

[Typescript] 인터페이스의 키 목록을 string 배열과 일치하도록 강제하기 – Under The Pencil

Declare a function with an Object return type in TypeScript | bobbyhadz

TypeScript: Handbook - Interfaces

테스트

javascript-testing-best-practices/readme.kr.md at master · goldbergyoni/javascript-testing-best-practices · GitHub

Configuration

NestJS Configuration. Configure your NestJS application with… | by Darwin Subramaniam | Medium

Externalizing application Configuration | by Hantsy | The Startup | Medium

Advanced Testing Strategies with Mocks - Trilon Consulting

도커 띄워서 테스트
Creating a NestJS application (Part II) | Jp Lindgren Tech blog

Config

GitHub - nestjsx/nestjs-config: Config module for nestjs using dotenv

Ultimate Guide: NestJS Config & Environment Variables [2022]

공부노트 코드 참고할만한거
GitHub - jujube0/nest-study

TypeScript
import { ConfigModule, ConfigType } from "@nestjs/config";  
import { TestingModule, Test } from "@nestjs/testing";  
import jwtConfig from "./jwt.config";  
describe("jwtConfig", () => {  
  let config: ConfigType<typeof jwtConfig>;  
  beforeEach(async () => {  
    const module: TestingModule = await Test.createTestingModule({  
      imports: [ConfigModule.forFeature(jwtConfig)],  
    }).compile();  
    config = module.get<ConfigType<typeof jwtConfig>>(jwtConfig.KEY);  
  });  
  it("should be defined", () => {  
    expect(jwtConfig).toBeDefined();  
  });  
  it("should contains expiresIn and secret key", async () => {  
    expect(config.expiresIn).toBe("3600s");  
    expect(config.secretKey).toBe("rzxlszyykpbgqcflzxsqcysyhljt");  
  });  
});  

AWS 세팅 등 참고할 실제 프로덕션 코드

GitHub - cspark0610/Mindfit-monorepo-nest


User Role 관련

Role based authentication in NestJS using Guards - Kuros.in

Soft Delete relation Cascade

To implement soft delete with relations in TypeORM, you can use the @DeleteDateColumn decorator instead of the @Column decorator on your entity’s delete date column. This will mark the entity as deleted by setting the delete date instead of actually deleting the row.

Then, to ensure that related entities are also marked as deleted, you can use the onDelete option with the @ManyToOne or @ManyToMany decorators to specify that related entities should be set to null or also marked as deleted when the parent entity is deleted.

Here is an example using NestJS:

TypeScript
@Entity()  
export class User {  
  @PrimaryGeneratedColumn()  
  id: number;  

  @Column()  
  name: string;  

  @DeleteDateColumn()  
  deletedAt: Date;  

  @OneToMany(() => Post, (post) => post.user, { onDelete: "CASCADE" })  
  posts: Post[];  
}  

@Entity()  
export class Post {  
  @PrimaryGeneratedColumn()  
  id: number;  

  @Column()  
  title: string;  

  @DeleteDateColumn()  
  deletedAt: Date;  

  @ManyToOne(() => User, (user) => user.posts)  
  user: User;  
}  

In this example, when a user is deleted, all related posts will be deleted as well. To change this behavior to mark the related posts as deleted instead, you can use the onDelete option with @ManyToOne to specify that posts should be set to null instead of deleted:

TypeScript
@ManyToOne(() => User, user => user.posts, { onDelete: 'SET NULL' })  

Or you can add a deletedAt column to the Post entity and use onDelete with @ManyToOne to specify that posts should also be marked as deleted:

TypeScript
@ManyToOne(() => User, user => user.posts, { onDelete: 'CASCADE' })  

Many to Many

Many-to-many relations - typeorm

  • Many-to-many relations with custom properties

In case you need to have additional properties in your many-to-many relationship, you have to create a new entity yourself. For example, if you would like entities Post and Category to have a many-to-many relationship with an additional order column, then you need to create an entity PostToCategory with two ManyToOne relations pointing in both directions and with custom columns in it

TypeScript
import { Entity, Column, ManyToOne, PrimaryGeneratedColumn } from "typeorm";  
import { Post } from "./post";  
import { Category } from "./category";  

@Entity()  
export class PostToCategory {  
  @PrimaryGeneratedColumn()  
  public postToCategoryId: number;  

  @Column()  
  public postId: number;  

  @Column()  
  public categoryId: number;  

  @Column()  
  public order: number;  

  @ManyToOne(() => Post, (post) => post.postToCategories)  
  public post: Post;  

  @ManyToOne(() => Category, (category) => category.postToCategories)  
  public category: Category;  
}  
TypeScript
  @ManyToOne(  
    () => User,  
    (user) => user.postConnections,  
    { orphanedRowAction: 'delete' },  
  )  
  user: User;  

  @ManyToOne(  
    () => Post,  
    (post) => post.postConnections,  
    { orphanedRowAction: 'delete' },  
  )  
  post: Post;  

On Cascade in 1:N Relation

SoftDelete in relationships cascade does not work · Issue #5877 · typeorm/typeorm · GitHub

// users.entity

TypeScript
@OneToMany(() => Comment, (comment) => comment.user, {  
    cascade: true,  
    onDelete: 'CASCADE',  
  })  
  comments: Comment[];  

  @OneToMany(() => UsersPress, (usersPress) => usersPress.user, {  
    cascade: true,  
    onDelete: 'CASCADE',  
  })  
  user_presses: UsersPress[];  

// soft remove part

TypeScript
const user = await this.usersRepository.findOne({  
  where: { id },  
  relations: [  
    "comments",  
    "user_presses",  
    "likes",  
    "notices",  
    "dislikes",  
    "usersShareParagraphs",  
  ],  
});  
await this.usersRepository.softRemove(user);  

에러

Rejected status from HTTP Request Node - Questions - n8n

  • 에러 로그
  1. Nest Js 로그
Bash
[Nest] 11444  - 02/14/2023, 9:10:34 PM   ERROR [TypeOrmModule] Unable to connect to the database. Retrying (2)...  
Error: connect ECONNREFUSED 127.0.0.1:5432  
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16)  
  1. DataGrip
Bash
java.sql.SQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:319) at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49) at org.postgresql.jdbc.PgConnection. (PgConnection.java:247) at org.postgresql.Driver.makeConnection(Driver.java:434) at org.postgresql.Driver.connect(Driver.java:291) in JdbcHelperImpl.connect(JdbcHelperImpl.java:639) Caused by: java.net.ConnectException: Connection refused (Connection refused) at java.base/java.net.PlainSocketImpl.socketConnect(Native Method) at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:412) at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:255) at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:237) at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.base/java.net.Socket.connect(Socket.java:609) at org.postgresql.core.PGStream.createSocket(PGStream.java:241) at org.postgresql.core.PGStream. (PGStream.java:98) at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:109) at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:235) at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49) at org.postgresql.jdbc.PgConnection. (PgConnection.java:247) at org.postgresql.Driver.makeConnection(Driver.java:434) at org.postgresql.Driver.connect(Driver.java:291) in JdbcHelperImpl.connect(JdbcHelperImpl.java:639) ... 1 more Suppressed: com.intellij.database.util.AsyncTask$Frame$FrameData: Async frame data:   -> Prepare connection -> Establish database connection -> Get database credentials -> Perform database connection  

Well seems like you have mixed the targets somehow. Make sure you production target is selected, then edit the db connection and enter the right production settings. Save and deploy.

Bash
 psql -h localhost -p 5432  
TypeScript
psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: Connection refused  
    Is the server running on that host and accepting TCP/IP connections?  

Postgresql : Connection refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections - Stack Overflow

Bash
sudo lsof -n -u postgres |grep LISTEN  

postgres가 안켜져있나.

Bash
$ pg_ctl -D /opt/homebrew/var/postgresql@14 start  

하니까 무슨 pg_ctl 파일이 없다고 함.

걍 재설치함

Bash
brew reinstall postgresql@14  

새로운 유저

JSON
{  
  user: User {  
    email: 'meetmigo@gmail.com',  
    username: '남극 미고',  
    deletedAt: null,  
    id: '290a6cd6-79eb-48c4-ad58-82c4b82cfd4e',  
    createdAt: 2023-02-14T13:17:51.034Z,  
    updatedAt: 2023-02-14T13:17:51.034Z  
  },  
  refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIyOTBhNmNkNi03OWViLTQ4YzQtYWQ1OC04MmM0YjgyY2ZkNGUiLCJ0b2tlblR5cGUiOiJyZWZyZXNoIiwiaWF0IjoxNjc2MzgwNjcxLCJleHAiOjIyODExODA2NzEsImp0aSI6IjE2ODJjMDE3LTlkOWMtNDEzMC1hMzk2LTU1ZWMwZTZjMGZiNSJ9.EJ98BSZRkbXAJSNEQzzFzRhwdXQ9UgHCrbtk448Ib0A',  
  accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIyOTBhNmNkNi03OWViLTQ4YzQtYWQ1OC04MmM0YjgyY2ZkNGUiLCJyZWZyZXNoVG9rZW5JZCI6IjE2ODJjMDE3LTlkOWMtNDEzMC1hMzk2LTU1ZWMwZTZjMGZiNSIsInRva2VuVHlwZSI6ImFjY2VzcyIsImlhdCI6MTY3NjM4MDY3MSwiZXhwIjoxNjc2NDEwNjcxLCJqdGkiOiI5OGFmODJjOS03ZDEyLTQ0N2QtOTQ3OS1jZjE3MTBiMDFmOTYifQ.TdfgFd0MbfqbBvwWT_ptrFraoEzJ70mgbcVnp5zDnbY',  
  message: 'login success'  
}  

2.20.월요일

A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with –detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.

All about those jest failures…. Our builds had started exhibiting some… | by Harsh S Kulshrestha | Debuide | Medium
–detectOpenHandles prints nothing, just hangs · Issue 9473 · facebook/jest · GitHub

–detectOpenHandles prints nothing, just hangs · Issue #9473 · facebook/jest · GitHub

스크립트 추가: jest --runInBand --detectOpenHandles

추가 개념: 자바스크립트 메모리 누수 Causes of Memory Leaks in JavaScript and How to Avoid Them

–detectOpenHandles
Attempt to collect and print open handles preventing Jest from exiting cleanly. Use this in cases where you need to use –forceExit in order for Jest to exit to potentially track down the reason. This implies –runInBand, making tests run serially. Implemented using async_hooks. This option has a significant performance penalty and should only be used for debugging.

Hello there, I write down everything as you posted but I still get warning i… - DEV Community 👩‍💻👨‍💻

–detectOpenHandles should help you find the non-closing process. It might also remove the message

–force-exit will make sure to kill the process and allow your test to run smoothly on CI environments. It is a bit barbaric but it gets the job done.

I’ve done a few tests before replying. The first screenshot does not use the –detectOpenHandles options and the seconds do.

An async function did not finish
A promise function did not finish
A Websocket, Database, or anything else that has connect/disconnect methods did not disconnect before the end of the test

앞으로 작업을 뭘 할지 적어라~!


마지막 업데이트 : 2025년 4월 23일
작성일 : 2023년 4월 2일