일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- JPA
- @Query
- router
- servicedata
- set
- SEO
- Login
- @Entity
- 리액트오류
- Polylang
- 구글
- ChatGPT
- 구글알고리즘
- 데이터베이스
- db
- post
- @Controller
- Thymeleaf
- GET
- @Repository
- HttpSession
- GA4
- 구글애널리틱스
- getapiurl
- 인텔리제이
- useContext
- firebase
- 플러그인
- 워드프레스
- useEffect
- Today
- Total
하루코딩 세싹이
[TypeScript] 실무에서 꼭 쓰는 유틸리티 타입 3종 - keyof, particial, Omit 본문
[TypeScript] 실무에서 꼭 쓰는 유틸리티 타입 3종 - keyof, particial, Omit
떼떼히 2025. 6. 5. 16:08타입을 정의할 때 사용하는 keyof T
keyof T는 TypeScript에서 특정 타입 T의 모든 키 이름을 유니온 타입으로 만들어주는 유틸리티 타입이다. 예를 들어 type User = { name: string; age: number }일 때, keyof User는 'name' | 'age'가 된다. 이는 타입 수준에서만 존재하며, 코드 실행 중에는 사용할 수 없고 주로 제네릭 함수에서 타입 안전한 키 접근이나 매핑 타입을 만들 때 활용된다.
keyof T는 T 타입의 키들(속성 이름들)을 가져온다. [P in keyof T]는 그 키들 각각에 대해 순회하고, ?는 선택적 속성으로 만든다는 뜻이다.
type Partial<T> = {
[P in keyof T]?: T[P];
};
keyof T는 TypeScript의 타입 수준 개념이라, 실행 시(console.log 등)에는 직접 사용할 수 없다. keyof는 컴파일 타임(작성할 때)에만 존재하고, 런타임(실행 시점)에는 사라지기 때문이다. 실제 객체에서 keyof처럼 속성 이름(key) 을 보고 싶을 때는 자바스크립트의 Object.keys()를 사용해야 한다.
Object.keys()는 실제 객체에서 key를 배열로 반환하므로 keyof T와 유사하게 동작하지만, 완전히 같지는 않다.
type User = {
name: string;
age: number;
};
const user: User = {
name: "Alice",
age: 25
};
// 이건 타입 수준에서만 존재함 (런타임에는 없음)
type UserKeys = keyof User; // 'name' | 'age'
// 런타임에서 key를 보고 싶으면 Object.keys 사용
console.log(Object.keys(user)); // ['name', 'age']
Particial<T> 이해하기
TypeScript의 유틸리티 타입(Utility Types)은 기존 타입을 변형하거나 조작하여 새로운 타입을 만드는 데 사용되는 내장 타입 도구이다. 코드의 재사용성을 높이고, 타입 선언을 간결하게 만들 수 있게 해준다. 그 중에서 partial<T>는 TypeScript에서 매우 자주 사용되는 유틸리티 타입 중 하나이다.
Partial<T>는 타입 T의 모든 속성을 선택적으로(optional) 만드는 타입이다. 즉, T가 갖고 있는 모든 프로퍼티에 ?가 붙은 것처럼 동작한다. Partial<T>는 객체의 일부만 수정하거나 업데이트할 때, 부분적인 정보만 있는 객체를 다룰 때, 초기화 시 기본값을 제외한 필드를 나중에 채울 때 사용한다.
type User = {
name: string;
age: number;
};
type PartialUser = Partial<User>;
// 위는 아래와 같음
// type PartialUser = {
// name?: string;
// age?: number;
// }
Particial<T> 사용하기
객체 일부만 업데이트 할 때
타입이 User이면 id, name, age 값을 다 받아야하지만, Particial<User>를 사용해서 일부 값만 받아 업데이트 할 수 있다. 아래의 예제는 age 값만 다시 받아 업데이트 한 예제이다.
type User = {
id: number;
name: string;
age: number;
};
function updateUser(user: User, updates: Partial<User>): User {
return { ...user, ...updates };
}
const oldUser: User = { id: 1, name: "Tom", age: 30 };
const updated = updateUser(oldUser, { age: 31 }); // name을 생략해도 OK
Redux Toolkit이나 Zustand에서 상태 일부만 갱신
type AppState = {
isDarkMode: boolean;
language: string;
userName: string;
};
const updateState = (state: AppState, patch: Partial<AppState>): AppState => {
return { ...state, ...patch };
};
const currentState: AppState = {
isDarkMode: false,
language: 'en',
userName: 'John',
};
const newState = updateState(currentState, { language: 'ko' });
에러 메시지 처리용 타입 만들기
Partial<Record<keyof T, V>>는 폼 에러 메시지를 다룰 때 아주 유용한 패턴이다.
type FormFields = {
username: string;
password: string;
};
type ErrorMessages = Partial<Record<keyof FormFields, string>>;
// 결과 예시:
const errors: ErrorMessages = {
username: "Username is required"
// password는 생략 가능
};
DeepPartial로 중첩 객체까지 선택적으로 만들기
type UserProfile = {
name: string;
contact: {
email: string;
phone: string;
};
};
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
const profile: DeepPartial<UserProfile> = {
contact: {
email: "test@example.com" // phone은 없어도 됨
}
};
API 요청 시 DTO로 사용
Partial은 PUT보다는 PATCH 요청에서 많이 사용된다.
type UserRequest = {
name: string;
age: number;
email: string;
};
// PATCH 요청: 일부 필드만 보낼 수 있음
const requestBody: Partial<UserRequest> = {
age: 28
};
Omit<T, K> 이해하기
Omit<T, K>는 TypeScript에서 타입 T에서 특정 키 K를 제거한 새로운 타입을 생성하는 유틸리티 타입이다. 예를 들어 Omit<User, 'password'>는 User 타입에서 password 속성을 제외한 타입을 만들며, 보안 정보 제거, 수정 불가능한 필드 제외, 폼 데이터 정의 등 실무에서 자주 사용된다. K에는 제거할 키 이름 하나 또는 'a' | 'b' 형태의 여러 키를 지정할 수 있다.
기본 문법은 아래와 같으며 T에는 원본 타입을 입력하고, K에는 제거할 키 이름(string, union 등 가능)을 입력한다.
// 기본 문법
Omit<T, K>
// 원본 타입
type User = {
id: number;
name: string;
email: string;
password: string;
};
// password 속성을 제거한 새 타입
type PublicUser = Omit<User, 'password'>;
// 이제 PublicUser에는 password 속성이 없음
const user: PublicUser = {
id: 1,
name: 'Alice',
email: 'alice@example.com'
};
아래의 예제를 보면 id, name, email로 이루어져 있는 User 타입에서 email을 제외한 UserWithoutEmail이라는 새로운 타입이 생성되는 걸 확인할 수 있다.
type User = {
id: number;
name: string;
email: string;
};
type UserWithoutEmail = Omit<User, 'email'>;
/* 결과 타입:
type UserWithoutEmail = {
id: number;
name: string;
};
*/
Omit<T, K> 사용하기
여러 키 제거
type Admin = Omit<User, 'id' | 'email'>;
/* 결과 타입:
type Admin = {
name: string;
};
*/
업데이트용 타입 만들기
데이터베이스의 ID나 생성일은 변경하지 않기 때문에, 업데이트 요청에서는 제외한 타입을 만드는 데 유용하다.
type Product = {
id: number;
name: string;
price: number;
createdAt: string;
};
type ProductUpdateRequest = Omit<Product, 'id' | 'createdAt'>;
React 컴포넌트에서 prop 제한
Link 컴포넌트는 type 속성이 필요 없으니 제거하고, href만 추가해서 사용한다.
type ButtonProps = {
type: 'submit' | 'button';
disabled: boolean;
onClick: () => void;
};
type LinkProps = Omit<ButtonProps, 'type'> & {
href: string;
};
'개발 준비 > ReactJS&TypeScript' 카테고리의 다른 글
[TypeScript] 타입스크립트와 함께 쓰는 함수형 컴포넌트, React.FC<Props> (0) | 2025.06.11 |
---|---|
[ReactJS] 절대경로 설정, Alias 사용하기 (0) | 2025.06.10 |
[ReactJS] 오류, A component is changing an uncontrolled input to be controlled (0) | 2025.05.26 |
[ReactJS] DOM 직접 제어하기, useRef, forwordRef, useImperativeHandle (0) | 2025.05.15 |
[ReactJS] PDF 다운로드 기능 구현하기, jsPDF + html2canvas (0) | 2025.05.13 |