타입스크립트를 좀 더 세련되게, 클린코드하게 작성하기!
유틸리티 타입을 잘 활용한다면 더욱 유지보수성 높고 잘 정의된 엄격한 타입을 정의할 수 있다😀
잘 만들어진 라이브러리들의 타입 정의 파일을 보면 이 유틸리티들을 굉장히 세련되게 잘 활용해두었다.
이를 본받아 나도 촘촘하고 쫜득한 타입을 작성하고 싶은데 막상 실제론 잘 생각나지 않을 때가 많다😅..
그래서 작성해보는 컨닝노트!
아래 예시들은 다 긁어온 거임. 하단에 출처있음
Partial<T>
T에 들어가는 프로퍼티를 선택적으로 사용할 수 있다!
interface Todo {
title: string;
description: string;
}
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}
const todo1 = {
title: "organize desk",
description: "clear clutter",
};
const todo2 = updateTodo(todo1, {
description: "throw out trash",
});
interface TODO
는 title
을 요구하지만 Partial
로 구성되었기 때문에 오류가 나지 않는다!
Required<T>
interface Props {
a?: number;
b?: string;
}
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 }; // ERROR
선택적 프로퍼티로 구성된 Props
타입이지만 Required
로 인해 필수로 설정되었다.
가끔 공통 타입을 돌려막기 하기 위해 속성들을 선택적으로 만드는 일들이 생긴다.
이 후 필수적으로 요구되는 컴포넌트에서도 선택적 요소가 되기 때문에 이로 인해 혼란이 빚어지는 경우가 있었는데, 해당 상황 때 Required
하여 디버깅에 더욱 용이한 코드를 작성할 수 있을 것 같다.
omit<T,K>
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Omit<Todo, 'description'>;
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
};
T에서 K를 제거한 타입을 구성한다.
Exclude<T,U>
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
T에서 U를 뺀 나머지를 구성한다.
Record<K,T>
interface PageInfo {
title: string;
}
type Page = 'home' | 'about' | 'contact';
const x: Record<Page, PageInfo> = {
about: { title: 'about' },
contact: { title: 'contact' },
home: { title: 'home' },
};
--- 하단의 인덱스 시그니쳐와 비슷함
type humanInfo = {
[index: string]: {title:string}
}
타입 T의 프로퍼티의 집합 K로 타입을 구성합니다.
사실, 이 유틸리티를 정리하고 싶어서 시작한 벨로그 글!
타입스크립트는 기본적으로 객체의 프로퍼티를 읽을 때 string
타입의 key 사용을 허용하지 않는다고 한다.
정확히는 string literal
타입만 허용된다.
이로 인해 어떤 string값을 가져와 이로 key를 찾으려고 하면 타입에러가 난다.
for (const key of Object.keys(obj)) {
console.log(obj[key]) // compile error! key가 string타입이다.
}
하지만 record를 사용하면, 더욱 보기 좋고 읽기 쉽게 프로퍼티를 맵핑할 수 있다!
난 이걸 모르고 그동안 인덱스 시그니쳐만 사용해왔다..
type humanType = {
name: string;
age: number;
address: string;
};
type humanRecordType = Record<keyof humanType, string>;
let human: humanRecordType = {
name: "또치",
age: "20",
address: "서울"
};
이거는 하단 출처의 블로그에서 발견한 사용 예시이다.
humanType을 Record로 다시 맵핑하여 string 값으로만 되어있는 타입을 구성했다.
깔끔하고 세련됐다😎
interface Todo {
title: string;
}
const todo: Readonly<Todo> = {
title: 'Delete inactive users',
};
todo.title = 'Hello'; // 오류: 읽기 전용 프로퍼티에 재할당할 수 없음
재할당이 일어나지 않게 한다는 것은, 내가 전달할 객체가 변하지 않을 것이라고 확신할 수 있다는 것!
함수 props에 readOnly를 주어서 불변성을 유지하는 안전장치를 마련할 수 있다.
계속 작성중..
부록. enum, uion type,
https://ajdkfl6445.gitbook.io/study/typescript/enum-type-union-type
출처
https://developer-talk.tistory.com/296
https://kyounghwan01.github.io/blog/TS/fundamentals/utility-types/#partial
https://typescript-kr.github.io/pages/utility-types.html
https://radlohead.gitbook.io/typescript-deep-dive/type-system/readonly