이번에는 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 |
