2022년 12월 12일 글입니다.
Item 27. 함수형 기법과 라이브러리로 타입 흐름 유지하기
요약 : 타입스크립트의 타입정보가 그대로 유지되는 타입흐름(flow)을 계속 전달되로록 하는 라이브러리들과 함수형 기법을 적극 사용하자.
> 로대시(Lodash)나 람다(Ramda)같은 함수형 프로그래밍 개념이 자바 스크립트에도 도입되고 있다.
- lodash 관련자료
기본적인 lodash의 사용방법을 적어놓겠다. 지금 익히기엔 너무 과한 것 같고, 나중에 개발할때 사용해야 겠다.
- 함수 내부적으로는 문자열 리터럴 타입과 인덱스 타입의 조합으로만 이루어져 있기 때문에, 타입이 자연스럽게 도출된다고 한다.
- 내장된 함수형 기법들과 로대시 같은 라이브러리에 타입 정보가 잘 유지되는데, 이는 함수 호출 시, 전달된 매개변수 값을 건드리지 않고 매번 새로운 값을 반환함 으로써, 새로운 타입으로 안저하게 반환할 수 있기 때문이다.
- 로대시나 내장된 함수형 기법들(map, filter 등등)을 쓰면 굳이 하나하나 타입구문이나 단언문을 쓰지 않아도 되서 적극 활용하는게 가독성 면과 효율성 면으로도 좋다고 한다.
4장. 타입설계
- 타입스크립트의 장점 : 데이터 타입을 명확히 알 수 있어 코드를 이해하기 쉽다.
- 그러니 그 중요한 타입을 설계하는 방법에 대해 알아보자!
Item 28. 유효한 상태만 표현하는 타입을 지향하기
요약 1 : 유효한 상태만 표현하는 타입을 지향해야 한다. 코드가 길어지거나 표현이 어려워질 수 있지만 결국은 시간을 절약하고 고통을 줄일 수 있다.
요약 2 : 유효, 무효한 상태를 둘 다 표현하는 타입은 혼란을 초래하기 쉽고 오류를 유발한다.
interface State {
pageText: string;
isLoading: boolean;
error?: string; //error가 optional로 선택된 것 부터 잘못됐다.
}
//이러면 isLoading이면서 error일때의 처리가 불가능해진다 == 무효한 상태
declare let currentPage: string;
//renderPage에는 etrror이면서 isLoading일때의 처리가 안되어있다.
//즉 무효한 상태를 표현하고 있다.
function renderPage(state: State) {
if (state.error) {
return `Error! Unable to load ${currentPage}: ${state.error}`;
} else if (state.isLoading) {
return `Loading ${currentPage}...`;
}
return `<h1>${currentPage}</h1>\n${state.pageText}`;
}
// 1. isLoading중에 에러가 발생했다면 isLoading을 false로 만들어야 하는데, 그런 코드가 없어서 에러가 던져져도 isLoading이 트루인 괴상망측한 상태가 된다.
//2 . state.e를 초기화하는 구문이 없기 때문에 과거의 에러메세지가 계속 추가된다.
//3. 페이지 로딩중에 사용자가 페이지를 바꿨을 시 , 어떤일이 일어날지 예상 하기 어렵다. text는 먼저 도착하는 순서대로 text를 출력할 것이기 때문이다.
async function changePage(state: State, newPage: string) {
state.isLoading = true;
try {
const response = await fetch(getUrlForPage(newPage));
if (!response.ok) {
throw new Error(`Unable to load ${newPage}: ${response.statusText}`);
}
const text = await response.text();
state.isLoading = false;
state.pageText = text;
} catch (e) {
state.error = '' + e;
}
그래서 위와 같은 코드를 아래처럼 개선해보자
//각각의 상태마다 타입을 지정한다.
//이렇게 되면 동시성을 띄는 상태가 없어지므로 무효한 상태를 표현할 수 없게 된다.
//태그된 유니온 기법을 사용했다.
interface RequestPending {
state: 'pending';
}
interface RequestError {
state: 'error';
error: string;
}
interface RequestSuccess {
state: 'ok';
pageText: string;
}
type RequestState = RequestPending | RequestError | RequestSuccess;
interface State {
currentPage: string;
requests: {[page: string]: RequestState};
}
function getUrlForPage(p: string) { return ''; }
//renderPage가 명확해졌다. 현재의 페이지를 받아와서 현재의 페이지의 응답을 기준으로 상태를 처리한다. 위 코드에서 봤던 loading이면서 error인 상태 없이 명확하게 분리되어 있다.
function renderPage(state: State) {
const {currentPage} = state;
const requestState = state.requests[currentPage];
switch (requestState.state) {
case 'pending':
return `Loading ${currentPage}...`;
case 'error':
return `Error! Unable to load ${currentPage}: ${requestState.error}`;
case 'ok':
return `<h1>${currentPage}</h1>\n${requestState.pageText}`;
}
}
// 1,2 . 로딩중에 에러가 발생한다면 바로 try~ catch문을 통해 에러를 던져준다. 에러는 {state:"error" , error:""+e}로 설정되기 때문에 에러메세지의 초기화와 상태의 설정이 동시에 된다.
//3. 페이지 로딩중에 사용자가 페이지를 바꿨을 시 , newPage로 인자가 들어오고 상태를 pending으로 변경한다. state.requests[newPage] newPagr를 인자로 받기때문에, 키값 설정에 따른 상태를 설정한다.즉 계속적으로 currentPage를 갱신해주기 때문에 명확한 것 같다.
async function changePage(state: State, newPage: string) {
state.requests[newPage] = {state: 'pending'};
state.currentPage = newPage;
try {
const response = await fetch(getUrlForPage(newPage));
if (!response.ok) {
throw new Error(`Unable to load ${newPage}: ${response.statusText}`);
}
const pageText = await response.text();
state.requests[newPage] = {state: 'ok', pageText};
} catch (e) {
state.requests[newPage] = {state: 'error', error: '' + e};
}
}
- 유효한 상태, 무효한 상태라는 말이 조금 헷갈리는데,
저자는 결국 active한 현재 상태만 제대로 표현하라고 하는 것 같다. 아직 살짝 이해하기 어렵지만 저자 말대로 case문으로 명확하게 하고, currentPage를 destructing으로 받아 오는 로직은 기억해 둘만 하다.
'Book Review > Effective Typescript' 카테고리의 다른 글
Day10_Effective Typescript 29~31 (0) | 2023.06.16 |
---|---|
Day8_Effective Typescript 스터디 (item 25~ 26) (0) | 2023.06.16 |
Day7_Typescript Effective 스터디 (item 22~24) (0) | 2023.06.16 |
Day6_Effective Typescript 스터디 (0) | 2023.06.16 |
day5_EffectiveTypescript 스터디 (0) | 2023.06.16 |