타입스크립트에서 기존 코드로부터 타입을 가져오는 법 ReturnType, ComponentProps
타입스크립트를 잘 사용하기 위한 여러 유틸 타입이 있다.
그중에서도 이미 잘 사용중이던 함수를 사용한다면, 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