Total Typescript - as

김동하·2025년 4월 12일
0

typescript

목록 보기
13/21
post-thumbnail

1. as with props

as라는 props를 받아 동적인 태그를 반환하는 Wrapper가 있다.

as에 따라서 props를 체킹해주고,

존재하는 attribute를 추론해주게 하고 싶다.

이런 비슷한 타입일 것이다. 하지만 as를 모두 작성할 수 없으니 IntrinsicElements를 활용하여 동적으로 적용해줘야 한다.

이런 식으로 HTML tag들을 잘 가져온다.

우리가 원하는 타입의 형태로 변경해주기 위해서는 Indexed access types를 활용하면 된다.

[keyof JSX.IntrinsicElements]를 붙이면

원하는 타입의 형태로 잘 나온다.

이제 WrapperProps 덕분에 사용할 수 있는 태그들이 자동완성된다.

마지막으로 ComponentProps까지 추가해주면

as에 따라 없는 props 를 검사하고

있는 props는 잘 추론하는 것을 확인할 수 있다.

또 다른 방법

위 방법말고 제네릭으로도 해결할 수 있다.

extendsComponentProps를 해준다.

제네릭으로 하는 방법으로 타입을 지정하게 되면 <Comp ... />에서 에러가 나온다.

props.as를 통해 전달된 값(Comp)은 JSX 요소로 렌더링되어야 하지만, 타입스크립트가 이를 JSX 요소로 사용할 수 있는 타입인지 확신하지 못하기 때문에 발생한 에러다.

as string 혹은 as keyof JSX.IntrinsicElemnts를 강제하면 해결된다.

2. as with custom components

그럼 이렇게 커스텀 컴포넌트를 넘기는 경우는 어떨까?

Custom을 as로 넘기게 되면 난리가 난다. 기존에 만들었던 Wrapper의 타입으로는 부족하다.

ComponentPropsWithoutRef

ComponentProps<TAs>가 props의 타입을 제대로 추론하지 못하는 있는 문제를 먼저 해결해보자.

Wrapper에서 ComponentProps 이 부분을 수정해야한다.

ComponentProps의 타입 데피니션 파일을 가보면

무언가 ComponentProps과 비슷해 보이는 ComponentPropsWithoutRefComponentPropsWithRef가 보인다.

주석에도 나와있든 ComponentPropsWithoutRefComponentPropsWithRef를 쓰길 권장하고 있다.

ComponentPropsWithoutRefElementType을 확장하고 있는데, ElementType의 타입 데피니션을 가보면

JSX.IntrinsicElemnts혹은 ComponentType를 반환하는 것을 알 수 있다!

Wrapper에서

ComponentProps -> ComponentPropsWithoutProps

그리고 keyof JSX.IntrinsicElemnts -> ElementType으로 변경한다.

이제 완벽하게 제대로 타입 검증을 한다.

마지막으로 Comp에 해줬던 as keyof JSX.In trinsicElemnts도 제거해도 문제가 없다.

3. as with default props

이제 조금 다른 예제를 살펴보자. Link 컴포넌트는 기본값으로 as = "a"를 받는다.

문제

기본값으로 as = "a" 태그임에도 불구하고 props의 attribute를 제대로 추론하지 못 하고 있다.

default generic

가장 쉬운 방법은 제네릭에 기본값을 주는 것이다.

기본값인 <a> 태그를 받아 제대로 attribute를 추론하고 있다.

하지만, 문제가 생겨버리는데 바로 자동완성 추론이 사라진다는 것이다.

타입스크립트는 기본값인 <a> 태그만 as의 타입으로 추론해버린다.

그래서 <TAs>조건부로 수정해줘야 한다.

a extend b ? c : d

언뜻보기에 TAs extends ElementType ? "a" : TAs 이 조건식이 맞아보이지만 틀렸다.

왜냐!? TAs는 이미 ElementType을 상속받았기 때문에 항상 참이 되기 때문이다.

즉, ElementType extends TAs ? "a" : TAs 반대로 찾아줘야 한다.

ElementType(더 넓은 타입)TAs(더 구체적인 타입)에 패스가 되냐를 따져하는 것이다.

당연히 대부분의 경우 false이므로 TAs로 추론되고, as 가 없는 경우만 "a"로 추론될 것이다.

이제 기본값을 충실하게 받으면서도 타입 체킹을 잘 해주는 녀석으로 거듭났다.

참고 : total typescript

profile
프론트엔드 개발

0개의 댓글