[TIL] TypeScript 3

Danbi Cho·2020년 8월 16일
0

TypeScript

목록 보기
3/4

이전에 TypeScript로 프로젝트를 진행한 경험이 있다. 이때, 완벽하게 이해하지 못하고 넘어갔던 코드나 개념을 다시 짚어보려고 한다.

// 실제 사용 예시
import { RouteComponentProps } from "react-router-dom";
const LogInView: React.FunctionComponent<RouteComponentProps> = (props) => {
  const goSignUpView = () => {
    props.history.push(`/signup`);
  };
}

React에서 컴포넌트 만드는 방법

클래스 기반 - 확장(extends)해서 사용

  • React.Componenet와 React.PureComponent는 shouldComponentUpdate 라이프 사이클 메소드를 다루는 방식을 제외하고는 같다.

React.Componenet

  • React.Component를 확장(extends) 해서 컴포넌트를 만들면, shouldComponentUpdate 메소드를 선언하지 않으면 컴포넌트는 props, state 값이 변경될 때마다 항상 리렌더링 된다.

React.PureComponent

  • shouldComponentUpdate 라이프 사이클 메소드가 이미 적용된 React.Component 클래스라고 보면 된다.
  • React.PureComponent를 확장(extends) 해서 컴포넌트를 만들면, shouldComponentUpdate 메소드를 선언하지 않아도 PureComponent 내부에서 props와 state를 shallow level 안에서 비교하고, 변경된 값이 있을 때에만 리렌더링 된다.

함수 기반

Functional Component

  • 함수 컴포넌트는 클래스 기반의 컴포넌트와 달리 state, 라이프 사이클 메소드(componentDidMount, shouleComponentUpdate 등)와 ref 콜백을 사용할 수 없다.
    (context는 사용 가능 / hooks API가 추가된 이후에는 함수 컴포넌트에서도 state 관리 가능)
  • 함수 컴포넌트는 state가 없고, 라이프 사이클도 신경 쓰지 않기 때문에 클래스 기반의 컴포넌트 보다 퍼포먼스가 좋다고 예상할 수 있지만 실제로 함수 컴포넌트도 클래스 기반 컴포넌트로 래핑(wrapping) 되기 때문에, 큰 차이는 없다.
  • 오히려 React.PureComponent에 shoulComponentUpdate를 통해 리렌더링을 최소화하기 때문에 React.Component와 함수 컴포넌트보다 더 빠를 수 있다.

🤔 항상 React.PureComponent를 사용하는 것이 좋을까?

  • 아니다. PureComponent는 shallow level로만 데이터를 비교하기 때문에, nested object 등의 변경된 데이터를 감지 하지 못한다.
  • 그렇기 때문에 React.Component의 shouldComponentUpdate를 직접 다뤄야 한다.
  • 또한, 모든 컴포넌트에 PureComponent를 사용하는 것이 오히려 컴포넌트를 더 느리게 할 수도 있다.

📌 클래스 컴포넌트(state, lifecyle, ref)가 필요한 상황이 아니면 항상 컴포넌트는 함수로 만드는 것이 좋다.

Shallow compare란?

  • shallow compare는 equility를 체크하는 것을 말한다.
  • 숫자나 문자열 같은 값들을 비교한다.
  • object를 비교할 때는 객체의 attribute(속성)을 비교하지 않고, 객체의 reference(참조)를 비교한다. 그렇기 때문에 같은 값이 들어있는 object라도 항상 다른 값으로 체크한다.

TypeScript에서 React Router 사용

  • 타입스크립트에서 리액트 라우터를 사용하려면 react-router-dom뿐만 아니라 타입 정보가 있는 @types/react-router-dom 패키지도 필요하다.
  • 위의 예시 코드에서 <RouteComponentProps> 처럼 RouteComponentProps를 제네릭으로 사용한다.
    이 때, Route를 통해 component에는 3개의 객체가 넘어온다.
    • history
      • 브라우저의 window.history와 비슷하다.
      • 주소를 임의로 변경하거나 되돌아갈 수 있게 한다.
      • 주소를 변경하더라도 SPA의 특성에 맞게 페이지 전체를 리로드 하지 않고 페이지 일부만 리로드 한다.
    • location
      • 브라우저의 window.location과 비슷하다.
      • 현재 페이지에 대한 정보를 가지고 있고, URL을 쪼개서 가지고 있다.
      • URL의 query 정보도 가지고 있다.
    • match
      • Route의 path에 정의한 것과 매치된 정보를 가지고 있다.

제네릭

  • 여러 타입에 대해 동작하는 함수를 정의하되, 해당 함수를 정의할 때는 알 수 없고 사용할 때에만 알 수 있는 타입 정보를 사용하려 할 때 제네릭을 사용한다.

타입 변수

  • 요소를 사용하는 시점에서만 알 수 있는 타입을 담아두기 위해서 타입 변수가 필요하다.
  • 타입 변수를 부등호(<>)로 변수명을 감싸 정의하고, 정의한 타입 변수를 요소의 타입 정의에 사용할 수 있다.

제네릭 함수

// 정의
function getFirstElem<T>(arr: T[]): T {
  /* 함수 본문 */
}
function 함수명<타입 변수>(인자 타입): 반환 타입 {
  /* 함수 본문 */
}

// 호출
const languages: string[] = ['TypeScript', 'JavaScript'];
const language = getFirstElem<string>(languages); // 이 때 language의 타입은 문자열
  • 위의 타입 정의는 임의의 타입 T에 대해, getFirstElem은 T 타입 값의 배열 arr를 인자로 받아 T 타입 값을 반환하는 함수를 말한다.

  • 제네릭 함수를 호출할 때는 정의에서 타입 변수가 있던 자리에 타입 인자를 넣어준다.

유니온 타입

function square(value: number, returnString: boolean = false): string | number {
  const squared = value * value;
  if (returnString) {
    return squared.toString();
  }
  return squared;
  • 위의 코드를 보면 함수 square은 숫자 타입과 불리언 타입의 인자를 받아 그 값에 따라 숫자 또는 문자열 타입의 값을 반환한다. 이 경우 반환 타입이 인자의 타입이 아닌 값에 의존한다.
  • 이 때 string 또는 number 타입 두 가지 경우의 수를 나타낸다.

인터섹션 타입

인터섹션 타입을 이용해 여러 경우에 모두 해당 하는 타입을 표현할 수 있다.

type Infeasible = string & number;

A & B 타입의 값은 A 타입과 B 타입에 할당 가능해야 한다. A와 B 모두 객체 타입이면 A & B 타입의 객체는 A와 B 타입 각각에 정의된 속성 모두 가져야 한다.

profile
룰루랄라! 개발자 되고 싶어요🙈

0개의 댓글