낙서장이자 오답 노트이자 컨닝 페이퍼
패스트캠퍼스 환급챌린지 24일차 : 코드팩토리의 백엔드 아카데미 : 한 번에 끝내는 NestJS 패키지 - 기초부터 MSA까지 강의 후기 본문
패스트캠퍼스 환급챌린지 24일차 : 코드팩토리의 백엔드 아카데미 : 한 번에 끝내는 NestJS 패키지 - 기초부터 MSA까지 강의 후기
NangIn 2025. 4. 24. 10:36본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
강의 내용 정리
Mapped Types 이론
Mapped Types란?
- 기존 타입(Class, Interface 등)을 기반으로 부분적인 수정/조합을 자동화해주는 TypeScript의 기능
- NestJS의 DTO 작성에서 코드 중복 제거에 매우 유용하게 사용됨
주요 5가지 Mapped Type
| 타입명 | 설명 |
| Partial<T> | 모든 프로퍼티를 옵셔널로 변경 |
| Pick<T, K> | 특정 프로퍼티만 골라 사용 |
| Omit<T, K> | 특정 프로퍼티만 제외하고 사용 |
| Intersection (A & B) | 여러 타입의 모든 프로퍼티를 병합 |
| Composition | 위 모든 Mapped Type을 조합하여 사용 |
예제 중심 사용법 요약
- Partial<T> – 가장 많이 사용하는 타입
- 모든 속성을 옵셔널로 만들 때 사용
-
export class CreateUserDto { name: string; email: string; password: string; } export class UpdateUserDto extends PartialType(CreateUserDto) {} - 사용 맥락:
- Create 시에는 모든 값이 필수
- Update 시에는 일부 필드만 수정될 수 있으므로 옵셔널 처리 필요
- Pick<T, K> – 원하는 속성만 골라 쓰기
-
export class LoginDto extends PickType(CreateUserDto, ['email', 'password']) {} - 사용 맥락:
- 이미 정의된 DTO에서 필요한 필드만 선택해 로그인, 조회 등에 활용
-
- Omit<T, K> – 특정 속성만 제외하고 쓰기
-
export class NoPasswordDto extends OmitType(CreateUserDto, ['password']) {} - 사용 맥락:
- 응답 시 민감한 필드를 제거하거나
- 특정 목적에 맞춰 DTO 간소화 시 유용
-
- IntersectionType(A, B) – 다중 DTO 병합
-
export class FullUserDto extends IntersectionType(UserDetailDto, AddressDto) {} - 사용 맥락:
- 여러 도메인 정보를 한 번에 응답할 때 유용
-
- Composition – 조합 활용
-
export class UpdateCatDto extends PartialType( OmitType(CreateCatDto, ['name'] as const), ) {} - 사용 맥락:
- 일부 필드는 제외하고, 나머지는 옵셔널 처리
- 유연하고 재사용성 높은 DTO 구성 가능
-
Mapped Types 적용하기
적용 대상: DTO 클래스 간 중복 제거
- CreateMovieDto, UpdateMovieDto를 비교해 보면,
- 구조는 동일하고
- Update에서는 @IsOptional()만 추가된 형태
- 이럴 경우, PartialType으로 Create DTO를 상속받으면 됨
PartialType 적용 방법
// Before
export class UpdateMovieDto {
@IsString()
@IsOptional()
title: string;
...
}
// After
export class UpdateMovieDto extends PartialType(CreateMovieDto) {}
- @nestjs/mapped-types에서 PartialType 불러와 사용
- CreateMovieDto의 모든 속성을 @IsOptional()로 감싸줌
- 실제로 클래스 밸리데이터에도 영향을 미침 → PATCH 요청 시 일부 필드만 보내도 통과 가능
Postman 테스트 예시
- /movies/1에 대해 title만 변경한 요청을 보냄:
- PATCH /movies/1 { "title": "Dark Knight Rise 300" }
- 성공적으로 요청 처리됨 → PartialType 적용으로 필수값 요구 사라짐
PartialType의 장점
| 항목 | 설명 |
| 중복 제거 | Create, Update DTO에서 동일한 필드 반복 정의 방지 |
| 유지보수 효율 | Create DTO만 수정해도 Update에 자동 반영 |
| 밸리데이션 연동 | @IsOptional() 적용 상태로 class-validator에서 정확히 처리 |
| Nest CLI 패턴 | NestJS CLI로 resource 생성 시 기본적으로 PartialType 사용 구조 제공 |
Genre/Director DTO에도 동일하게 적용
-
// UpdateGenreDto export class UpdateGenreDto extends PartialType(CreateGenreDto) {} // UpdateDirectorDto export class UpdateDirectorDto extends PartialType(CreateDirectorDto) {} - 모든 Update DTO의 중복 선언 제거
- 확장성 향상: Create DTO만 수정하면 Update까지 반영됨
Serialization
Serialization이란?
- 의미: 서버에서 프론트엔드로 데이터를 응답하기 전에 불필요한 필드를 제거하거나 변환하는 과정
- 사용 목적
- 민감하거나 내부 용도의 필드를 숨기기 위해
- 응답 데이터를 간결하고 명확하게 만들기 위해
- 프론트에서 불필요한 처리 비용 감소
현재 문제 상황
- /movies 요청 시 다음과 같은 불필요한 필드가 노출됨:
- __v: TypeORM 버전 필드 (내부용)
- updatedAt: 프론트에서는 보통 필요 없음
- createdAt: 경우에 따라 필요 없을 수 있음
{ "id": 1, "title": "Inception", "createdAt": "2024-01-01T00:00:00Z", "updatedAt": "2024-01-02T00:00:00Z", "version": 0 }
해결 방법 – class-transformer 사용
- NestJS는 class-transformer의 데코레이터를 통해 응답 데이터 필드를 조정할 수 있음
- 불필요한 필드 숨기기
-
@Exclude() // 엔티티 상단 혹은 프로퍼티마다 사용 updatedAt: Date; @Exclude() version: number; - @Exclude()는 직렬화 시 해당 필드를 제거
- 엔티티에 직접 명시하여 모든 응답에서 일괄적으로 적용 가능
-
- 필요한 필드만 노출하고 싶을 때 (선택적)
-
@Expose() title: string; - @Expose()만 명시한 경우, 해당 필드만 직렬화 대상으로 허용됨
-
적용 예시 – 무비, 장르, 다이렉터
- @Exclude()를 아래 필드에 적용:
-
@Exclude() updatedAt: Date; @Exclude() version: number;
-
- 각 엔티티 또는 공통 상속 클래스(예: BaseEntity)에서 처리 가능
결과 확인 (Postman 등)
- 요청 결과에서 해당 필드가 더 이상 출력되지 않음
- 응답이 훨씬 간결하고 깔끔하게 정리됨
학습 후기
Mapped Types는 단순히 TypeScript의 문법 요소 중 하나라고 생각했지만, NestJS에서 DTO를 다룰 때 실질적으로 엄청난 효율을 가져다주는 도구임을 실감했습니다. 특히 PartialType을 사용하면 Create DTO의 구조를 그대로 유지하면서도 Update DTO에서 모든 속성을 옵셔널로 처리할 수 있어, 코드 중복을 줄이고 유지보수까지 쉬워집니다. 클래스 밸리데이터와도 연동되기 때문에, 실제 요청 데이터의 유효성 검사까지도 완벽하게 대응할 수 있었습니다.
PickType과 OmitType도 필요에 따라 유용하게 쓸 수 있지만, 가장 빈도가 높은 것은 확실히 PartialType이었습니다. 실무에서는 대부분의 리소스가 Create와 Update 요청을 따로 받기 때문에, 이 두 DTO 간의 관계를 PartialType 하나로 해결할 수 있는 것은 매우 실용적인 방식입니다. 또한, Create DTO에만 수정이 발생해도 Update DTO에 자동으로 반영되기 때문에, 확장성과 유지보수 측면에서도 큰 이점이 있었습니다.
Serialization은 단순히 보기 좋은 응답을 만드는 작업 정도로 여겼지만, 실제로는 민감 정보나 불필요한 데이터가 노출되는 것을 방지하는 보안적인 측면도 있다는 걸 알게 됐습니다. 클래스에서 @Exclude() 데코레이터 하나로 프론트엔드 응답에서 특정 필드를 제거할 수 있는 기능은 아주 직관적이고 강력했습니다. 특히 version, updatedAt처럼 프론트에서는 필요 없는 필드들이 기본적으로 포함되어 있다는 사실을 보고, 이를 자동으로 관리해주는 방식이 얼마나 중요한지 체감할 수 있었습니다.
결론적으로 Mapped Types와 Serialization은 NestJS의 DTO 설계를 단순히 타입 선언으로 끝내지 않고, 코드의 일관성과 응답 구조의 명확성을 함께 보장해주는 핵심 도구였습니다. 실무에서 유지보수성과 안정성을 고려할 때 반드시 습득하고 적용해야 할 기능이라고 느꼈습니다.
학습 인증샷



