TypeScript 유틸리티 타입 Partial<T> – 부분만 채워도 되는 타입 만들기

2025. 12. 14. 19:59·FrontEnd/TypeScript

이번에는 Partial<T>를 정리해 본다

앞에서

  • Pick<T, K>는 필요한 필드만 골라서 쓰는 타입
  • Omit<T, K>는 필요 없는 필드만 빼고 쓰는 타입

이었다면,

Partial<T>는 한 줄로 이렇게 볼 수 있다.

"이 타입에 있는 모든 프로퍼티를 전부 optional로 바꿔 줘"

 


1. Partial 한 줄 정의

Partial<T>는

  • 타입 T에 있는 모든 프로퍼티를
  • "있어도 되고, 없어도 되는" 상태로 만들어 주는 유틸리티 타입이다.
type User = {
  id: number
  name: string
  email: string
}

type UserUpdate = Partial<User>
// 아래와 같은 구조로 인식된다
// {
//   id?: number
//   name?: string
//   email?: string
// }

 

UserUpdate 타입은

  • id만 있어도 되고
  • name만 있어도 되고
  • 셋 다 있어도 되고
  • 심지어 아무 것도 없어도 된다

라는 의미다.


2. 기본 사용 예시

2-1. 부분 업데이트용 타입 만들기

실무에서 제일 바로 떠올리는 용도는 "수정용 payload"다.

type User = {
  id: number
  name: string
  email: string
  avatarUrl?: string
}

type UpdateUserPayload = Partial<User>

function updateUser(id: number, payload: UpdateUserPayload) {
  // name만 바꾸고 싶으면 name만 보내면 된다
}

사용 예

updateUser(1, { name: "새 이름" })          // OK
updateUser(1, { email: "new@example.com" }) // OK
updateUser(1, {})                           // 이것도 타입상 OK

여기서 한 가지가 보인다.

타입만 보면 아무 필드도 없이 호출해도 허용된다.

 

그래서 실제로는 이걸 그대로 API 레이어까지 끌고 가기보다
"상황에 맞게 한 번 더 좁혀서" 쓰는 것이 좋다.


3. Pick / Omit과 함께 쓰는 패턴

Partial<T>는 단독보다 Pick, Omit과 조합해서 쓸 때 훨씬 더 많이 쓰게 된다.

3-1. 일부 필드만 부분 업데이트

예를 들어 글 수정 화면을 생각해 보자.

type Post = {
  id: string
  title: string
  content: string
  status: "draft" | "published"
  createdAt: string
  updatedAt: string
}

이 중에서 제목과 내용만 수정 가능하다고 하면

type PostEditableFields = Pick<Post, "title" | "content">

// 수정 시에는 둘 다 옵션으로
type UpdatePostPayload = Partial<PostEditableFields>

결과적으로

// {
//   title?: string
//   content?: string
// }

이렇게 만들어진다.

장점

  • "어떤 필드를 수정할 수 있는지"와
  • "그 필드들이 옵션이라는 것"을 분리해서 표현할 수 있다.

3-2. Omit과 함께 쓰는 패턴

Omit과도 자주 섞는다.

type User = {
  id: number
  name: string
  email: string
  password: string
  createdAt: string
  updatedAt: string
}

// 비밀번호는 건드리지 않고 나머지만 부분 업데이트
type UserUpdatableFields = Omit<User, "password">

type UpdateUserPayload2 = Partial<UserUpdatableFields>

이렇게 하면

  • password는 아예 포함되지 않고
  • 나머지 필드는 있어도 되고 없어도 되는 구조가 된다.

4. 실무에서 Partial가 유용한 순간

4-1. 폼 양식 "초기값 + 서버 응답" 처리

폼 상태를 객체 하나로 관리할 때가 많다.

type ProfileForm = {
  name: string
  nickname: string
  bio: string
}

처음에는 서버에서 가져온 값이 없을 수 있고

그래서 상태 타입을 이렇게 잡는 경우가 많다.

type ProfileFormState = Partial<ProfileForm>

const [form, setForm] = useState<ProfileFormState>({})

이 상태에서 서버 응답을 머지할 때도 자연스럽다

setForm(prev => ({
  ...prev,
  ...fetchedData, // 부분 데이터만 와도 문제 없음
}))

다만 이 경우에도

  • 실제로 제출할 때는 값이 비어 있으면 안 되기 때문에
  • 제출 직전에는 유효성 검사나 ProfileForm 타입으로의 변환이 필요하다.

4-2. "수정용 DTO" 타입 만들기

백엔드에서 많이 쓰는 패턴 그대로 프론트 타입에도 가져올 수 있다.

type Article = {
  id: string
  title: string
  body: string
  tags: string[]
  isPublished: boolean
}

// 새 글 생성
type CreateArticlePayload = Pick<Article, "title" | "body" | "tags">

// 수정
type UpdateArticlePayload = Partial<CreateArticlePayload>

이렇게 하면

  • 생성은 필수 필드만 모두 받아야 하고
  • 수정은 그중 일부만 보내도 된다.

이 구조가 코드에 그대로 녹아 들어간다.


5. Partial 쓸 때 주의할 점

Partial<T>는 편한 만큼, 남발하면 타입 안정성이 확 떨어진다.

5-1. "아무 것도 없어도 된다"는 뜻을 항상 기억하기

Partial<User>는 "User의 필드가 다 옵션"이라서
극단적으로는 {}도 허용한다.

이걸 잊으면 이런 코드가 나올 수 있다.

type User = {
  id: number
  name: string
}

type UpdateUserPayload = Partial<User>

function updateUser(payload: UpdateUserPayload) {
  // payload.name을 바로 쓴다면?
  console.log(payload.name.toUpperCase()) // 컴파일 에러
}

payload.name은 string | undefined이기 때문에
바로 toUpperCase()를 쓰면 안 된다.

즉

  • Partial을 쓴 타입은
  • 실제로 사용할 때 매번 존재 여부를 체크해야 한다.
if (payload.name) {
  console.log(payload.name.toUpperCase())
}

5-2. 진짜 "부분만 들어와도 된다"는 의미일 때만 쓰기

가끔 이런 코드가 나온다

type LoginForm = {
  email: string
  password: string
}

type LoginRequest = Partial<LoginForm>

로그인 요청에 email이나 password가 없어도 된다는 의미가 된다.

현실적으로는 이건 말이 안 된다.

이럴 땐

  • Partial을 쓰는 대신
  • 애초에 LoginForm은 둘 다 필수 타입으로 둔 채
  • 필요하면 기본값이나 폼 레벨에서만 optional 처리를 하는 편이 낫다.

Partial은

"없어도 되는 경우가 실제로 존재한다"

 

이게 분명할 때만 쓰는 게 좋다.


6. 정리 – Partial를 떠올리면 좋은 상황

나중에 이 시리즈 다시 볼 때를 위한 메모.

이럴 때 Partial<T>를 먼저 떠올려 보기.

  • 기존 타입의 필드를 전부 옵션으로 바꾸고 싶을 때
  • "부분 업데이트"나 "일부 필드만 들어오는 응답"을 표현하고 싶을 때
  • Pick, Omit으로 먼저 필드를 좁혀 둔 다음
    그 필드들을 전부 optional로 바꾸고 싶을 때

그리고

  • 로그인, 회원가입처럼 필수 값이 명확한 경우에는
    습관적으로 Partial을 쓰지 않기
  • Partial을 쓴 타입을 사용할 때는
    실제로 값이 있는지 체크하는 코드가 반드시 따라와야 한다는 점을 잊지 않기

Partial은 "대충 느슨하게 만들자"는 용도가 아니라
"부분만 들어와도 되는 상황을 정확하게 표현하자"에 가깝게 쓰는 게 더 안전하다

저작자표시 비영리 변경금지 (새창열림)

'FrontEnd > TypeScript' 카테고리의 다른 글

TypeScript as const 이게 뭘까  (0) 2025.12.18
TypeScript 유틸리티 타입 Omit<T, K> – 필요 없는 필드만 쏙 빼고 쓰기  (0) 2025.12.14
타입연산자 typeof, keyof, keyof typeof 패턴 정리  (0) 2025.12.14
TypeScript 유틸리티 타입 Pick<T, K> – 객체 타입에서 필요한 것만 뽑아 쓰기  (0) 2025.12.13
setTimeout() 반환값 정리 – 브라우저 vs Node에서 뭐가 다른지  (0) 2024.11.24
'FrontEnd/TypeScript' 카테고리의 다른 글
  • TypeScript as const 이게 뭘까
  • TypeScript 유틸리티 타입 Omit<T, K> – 필요 없는 필드만 쏙 빼고 쓰기
  • 타입연산자 typeof, keyof, keyof typeof 패턴 정리
  • TypeScript 유틸리티 타입 Pick<T, K> – 객체 타입에서 필요한 것만 뽑아 쓰기
프론트엔드 개발자 jbeat
프론트엔드 개발자 jbeat
프론트엔드 개발자 블로그인데 일상도 쪼그으믐
  • 프론트엔드 개발자 jbeat
    jbeat 님의 블로그
    프론트엔드 개발자 jbeat
  • 전체
    오늘
    어제
    • 분류 전체보기 (44)
      • FrontEnd (43)
        • TypeScript (6)
        • JavaScript (18)
        • Next.js (3)
        • React (1)
        • Testing (2)
        • Third Party (1)
        • web (10)
        • Tooling (1)
        • coding test (0)
        • A.I (1)
      • 일상 (1)
        • wedding (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    omit
    CRDT
    컬렉션
    이터러블
    주니어
    playwright
    CrossOrigin
    타입스크립트
    javascript
    preconnect
    Next.js
    고차함수
    TypeScript
    yjs
    Utility
    WebSocket
    Android
    배열
    코테
    pick
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
프론트엔드 개발자 jbeat
TypeScript 유틸리티 타입 Partial<T> – 부분만 채워도 되는 타입 만들기
상단으로

티스토리툴바