ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 이펙티브 타입스크립트- 3장 타입추론 (4)
    TypeScript 2022. 4. 18. 20:55

    아이템 24. 일관성 있는 별칭 사용하기

    객체의 프로퍼티를 코드 내에서 간결하게 사용하기 위해 별칭(Alias)을 추가하는 경우, 일관되지 않은 이름으로 혼란을 줄 수 있다.

    function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
      const box = polygon.bbox; // bbox, box라는 서로 다른 이름이 쓰이고 있다.
    
      if (box) {
        // ...
      }
    }

     

    일관된 이름을 사용하기 위해서는 구조분해 할당(destructuring)을 사용하는 것이 좋다. 단, 여전히 별칭을 사용하고 있기 때문에, polygon.bbox와 지역변수 bbox의 타입은 같더라도 값은 서로 달라질 수 있다는 점을 알아두자.

    function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
      const { bbox } = polygon;
    
      if (bbox) {
        // ...
      }
    }

     


    요약 

    • 별칭은 타입스크립트가 타입을 좁히는 것을 방해한다. 따라서 변수에 별칭을 사용할 때는 일관되게 사용해야 한다.
    • 새로운 변수 별칭 보다는 객체 비구조화를 고려하자
    • 함수 호출이 객체 속성의 타입 정제를 무효화할 수 있다는 점을 주의해야 한다. 속성보다 지역 변수를 사용하면 타입 정제를 믿을 수 있다.

    아이템 25. 비동기 코드에는 콜백 대신 async 함수 사용하기 

    비동기 함수를 작성할 때 콜백보다는 프로미스, 프로미스보다는 async/ await를 사용해야 하는 것이 코드 작성과 타입 추론을 쉽게 한다. 

    ES2015이전에는 비동기 동작을 위해 콜백을 사용했고 이는 콜백지옥 필연적으로 낳았다.

     

    하지만 ES2015의 Promise와 ES2017의 async/await 덕분에 비동기 코드의 가독성을 크게 개선되었다.

    // 병렬적으로 페이지를 로드하고 싶은 경우
    
    async function fetchPages() {
      const [response1, response2, response3] = await Promise.all([
        fetch(url1), fetch(url2), fetch(url3)
      ]);
      // ...
    }
    
     // 처음으로 처리된 프로미스가 생겼을 때 완료하고 싶은 경우
    
    async function fetchPages() {
      const [response1, response2, response3] = await Promise.race([
        fetch(url1), fetch(url2), fetch(url3)
      ]);
      // ...
    }
    
    // 타임아웃 추가하기
    function timeout(ms: number): Promise<never> {
      return new Promise((resolve, reject) => {
        setTimeout(() => reject('timeout'), ms);
      });
    }
    async function fetchWithTimeout(url: string, ms: number) {
      return Promise.race([fetch(url), timeout(ms)];
    }

    위에서 fetchWithTimeout은 리턴값의 타입을 명시하지 않아도 Promise<Response>로 타입이 잘 추론된다. Promise.race의 반환타입은 입력 타입들의 유니온이다. fetch(url)은 Promise<Response>, timeout(ms)는 Promise<never> 타입을 반환하기 때문에 Promise<Response | never>가 되고, never가 공집합이기 때문에 결국 Promise<Response>가 되는 것이다.

     

    일반적으로 프로미스를 생성하기 보다 async/await를 사용해야 하는 이유는 

    1. 더 간결하고 직관적인 코드가 된다.
    2. async 함수는 항상 프로미스를 반환하도록 강제한다. 
    const getNumber = async () => 42; // 타입이 () => Promise<number>

     

    함수는 항상 동기 또는 비동기로 실행되어야 하며 절대 혼용해서는 안된다.

     

    async 함수에서 프로미스를 반환하면 또 다른 프로미스로 래핑되지 않는다. 반환 타입은 Promise<Promise<T>>가 아닌 Promise<T>가 된다. 타입스크립트를 사용하면 타입 정보가 명확히 드러나기 때문에 비동기 코드의 개념을 잡는데 도움이 된다.

    // function getJSON(url: string): Promise<any>
    async function getJSON(url: string) {
        const response = await fetch(url);
        const jsonPromise = response.json(); // 타입이 Promise<any>
        return jsonPromise;

    요약 

    • 콜백보다는 프로미스를 사용하는 게 코드 작성과 타입 추론 면에서 유리하다
    • 프로미스보다는 async와 await를 사용하는게 간결하고 직관적 코드를 작성하여 오류를 제거하기 쉽다.
    • 어떤 함수가 프로미스를 반환한다면 async로 선언하는 것이 좋다. 

     

    댓글

Designed by Tistory.