TypeScript

타입스크립트에서 기존 코드로부터 타입을 가져오는 법 ReturnType, ComponentProps

citron031 2024. 9. 18. 19:22

타입스크립트를 잘 사용하기 위한 여러 유틸 타입이 있다.

 

그중에서도 이미 잘 사용중이던 함수를 사용한다면, ReturnType을 통해서 해당 함수의 반환값 타입을 쉽게 얻을 수 있다.

 

ReturnType

 

function getUser() {
  return {
    name: "Alice",
    age: 30,
  };
}

 

이런 함수가 있을 때, 이 함수의 리턴값 타입을 재사용하고자 하는 경우를 생각해보자.

interface getUserReturnValue {
  name: string;
  age: number;
}

 

이렇게 타입을 직접 작성할 수도 있지만, 만약 getUser 함수의 리턴값이 바뀌는 작업이 일어나면 타입도 직접 바꿔줘야 한다.

그리고 사람이 작성하는 코드이기에, 실수가 일어나기 더 쉬워보인다.

 

때문에 다음과 같이 작성하는 방법을 사용할 수 있다.

type User = ReturnType<typeof getUser>;

 

ReturnType 유틸 타입이 자동으로 함수의 리턴값을 추론해주므로, 아주 편리하게 타입을 가져와 사용할 수 있다.

 

ComponentProps

 

그리고, 비슷한 케이스로 React를 사용하면, Props에 타입을 작성하게 되는데 이 Props는 때때로 여러번 사용될 경우가 있다.

 

맨 처음 컴포넌트를 작성하며 Props의 타입을 작성하는 경우는 다음과 같은 예제로 표현할 수 있다.

type ButtonProps = {
  label: string;
  onClick: () => void;
};

const Button = (props: ButtonProps) => {
  return <button onClick={props.onClick}>{props.label}</button>;
};

 

해당 버튼에 대한 Props를 작성해준다.

 

그런데 만약 같은 Props를 전달받는 OutlintedButton 컴포넌트가 있다면, 어떻게 하는 것이 좋을까?

 

type OutlintedButtonProps = {
  label: string;
  onClick: () => void;
};

const OutlintedButton  = (props: ButtonProps) => {
  return <button 
             style={{ background: "#000", color: "#fff" }} 
             onClick={props.onClick}
         >{props.label}</button>;
};

 

같은 타입을  두 번 선언하는 것이 좋을까?

 

이런 경우에는 ComponentProps를 사용하여 기존의 Button 컴포넌트로부터 Props의 타입을 가져올 수 있다.

 

import { ComponentProps } from "react";
import Button from "./Button";


const OutlintedButton  = (props: ComponentProps<typeof Button>) => {
  return <button 
             style={{ background: "#000", color: "#fff" }} 
             onClick={props.onClick}
         >{props.label}</button>;
};

 

 

이렇게 하면 중복으로 Props를 선언하는 일 없이 동일한 타입을 사용할 수 있다.

 

👻 하지만, ComponentProps는 정말 유용할까?

그러나 컴포넌트를 생성할 때 Props에 대한 타입은 자연스럽게 만들게 된다.

 

그렇다면, ComponentProps를 사용하는 일 없이 export한 타입을 import하여 사용하면 그만이지 않을까?

 

거기에 컴포넌트에 추가 기능이 생기면서 Props가 추가되기라도 하면, 기존에 선언한 타입에 추가로 타입을 extends를 하여 확장하는 것이 더 바람직해 보인다.

(ComponentProps로 가져온 타입에 extends하는 것 보다 가독성이 나아  보기 깔끔할지도 모른다...)

 

 

때문에, 완전히 동기화된 컴포넌트에서는 ComponentProps가 유용할 수 있지만, 대다수의 경우에은 선언한 타입을 import하는 것으로 충분하지 않을까 하는 생각이 들었다.

 

🎶 ComponentProps는 특수한 상황에서 효과적이고, 특히 외부에서 전달된 컴포넌트를 사용하는 경우가 제일 좋은 사용처 같다.

  • 다른 사람이 작성한 라이브러리 컴포넌트를 불러와 사용하는 경우 (사실 이 경우에도, 해당 라이브러리 내부에 type을 export하는 경우가 대부분인듯)

 

✨ ReturnType역시 이미 존재하는 함수에서 타입을 가져오기 때문에, ComponentProps처럼 사용처가 애매한 것 같다.

그래도, 함수의 경우에는 자동으로 리턴 타입을 추론해주는 경우가 많기에 따로 리턴 타입을 작성하지 않는 경우가 있고, 이 경우에는 유용하게 사용될 수 있을 것 같다.

 

 

https://www.totaltypescript.com/react-component-props-type-helper

 

ComponentProps: React's Most Useful Type Helper

Discover the power of ComponentProps in React and TypeScript.

www.totaltypescript.com

https://www.typescriptlang.org/ko/docs/handbook/utility-types.html#returntypetype

 

Documentation - Utility Types

Types which are globally included in TypeScript

www.typescriptlang.org