타입 흐름을 개선하고, 가독성을 높이고, 명시적인 타입 구문의 필요성을 줄이기 위해 직접 구현하기보다는 내장된 함수형 기법과 lodash 같은 유틸리티 라이브러리를 사용하는 것이 좋다.
interface State {
pageText: string;
isLoading: boolean;
error?: string;
}
function renderPage(state: State) {
if (state.error) return `Error! Unable to load ${currentPage}`;
else if (state.isLoading) return `Loading ${currentPage}...`;
return `<h1>${currentPage}</h1>`;
}
👎 조건이 명확히 분리되어 있지 않아서 isLoading이 true이고 동시에 error 값이 존재하면 로딩 중인 상태인지 오류가 발생한 상태인지 명확히 구분히 불가능하다
✔️ 개선 방법
interface RequestPending {
state: "pending";
}
interface RequestError {
state: "error";
error: string;
}
interface RequestSuccess {
state: "ok";
pageText: string;
}
type ReqeustState = RequestPending | RequestError | RequestSuccess;
interface State {
currentPage: string;
requests: { [page: string]: RequestState };
}
function renderPage(state: State) {
const { currentPage } = state;
const requestState = state.requests[currentPage];
switch (requestState.staet) {
case "pending":
return `Loading ${currentPage}...`;
case "error":
return `Error! Unable to load ${currentPage}`;
case "ok":
return `<h1>${currentPage}</h1>`;
}
}
👍 네트워크 요청 과정 각각의 상태를 명시적으로 모델링하는 태그된 유니온을 사용하여 무효한 상태를 허용하지 않도록 개선.
효과적으로 타입을 설계하려면, 유효한 상태만 표현할 수 있는 타입을 만들어 내는 것이 가장 중요하다.
✔️ 사용하기 편한 API 일수록 반환 타입이 엄격하다.
✔️ 보통 매개변수 타입은 반환 타입에 비해 범위가 넓은 경향이 있다. 선택적 속성과 유니온 타입은 반환 타입보다 매개변수 타입에 더 일반적이다.
✔️ 매개변수와 반환 타입의 재사용을 위해서 기본 형태(반환 타입)와 느슨한 형태(매개변수 타입)를 도입하는 것이 좋다.