return ( <div> {/* Separate elements if not closed on the same line to make the code clearer */} {/* ❌ */} <div> <div> <p>Lorem ipsum</p> <p>Pellentesque arcu</p> </div> <p>Lorem ipsum</p> <p>Pellentesque arcu</p> </div> <div> <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque arcu. Et harum quidem rerum facilis est et expedita distinctio. </p> <p>Pellentesque arcu</p> <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque arcu. Et harum quidem rerum facilis est et expedita distinctio. </p> </div> {/* ✅ */} <Wrapper> <div> <p>Lorem ipsum</p> <p>Pellentesque arcu</p> </div> <p>Lorem ipsum</p> <p>Pellentesque arcu</p> </Wrapper> <div> <div> <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque arcu. Et harum quidem rerum facilis est et expedita distinctio. </p> <p>Pellentesque arcu</p> <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque arcu. Et harum quidem rerum facilis est et expedita distinctio. </p> </div> </div> </div> ); }
// ❌ directly using momemt import moment from"moment";
constupdateProduct = (product) => { const payload = { ...product, // ❌ we are bound to the moment interface implementation updatedAt: moment().toDate(), };
// Props<T>는 ComponentPropsWithoutRef<T>에 이 값을 그대로 넘겨준다. // 그리고 커스텀 프로퍼티 내부의 as에도 T 타입을 바인딩해준다. typeTextProps<T> = Combine<TextBaseProps<T>, ComponentPropsWithoutRef<T>>;
하지만, 이는 오류를 발생시킨다. ComponentPropsWithoutRef가 받을 수 있는 제네릭 타입이 ElementType으로 정해져 있기 때문이다.
즉, 이 중 한곳이라도 T에 대해서 명확하게 알 수 있다면 나머지 부분에서도 자연스럽게 추론이 가능하다.
as 프로퍼티로 타이핑 추상화 하기
as라는 프로퍼티는 Text 컴포넌트 뿐만 아니라 다양한 컴포넌트에서도 사용될 수 있기에 이 부분을 최대한 추상화 해둘 필요가 있다.
1 2 3 4 5 6 7 8
// 텍스트 컴포넌트의 프로퍼티 typeTextBaseProps = { typography?: string; };
// T 타입을 추론할 수 있는 as 프로퍼티를 자동으로 포함하고 // T 타입으로 HTML 엘리먼트 속성까지 타이핑 해주는 OverridableProps! typeTextProps<T extendsElementType> = OverridableProps<T, TextBaseProps>;
OverridableProps 타입은 특정 컴포넌트가 as 프로퍼티를 사용하여 HTML 요소 이름을 받고 내부적으로 해당 요소의 속성 타입을 찾아 바인딩해주는 함수이다.
이렇게 필요한 부분을 추상화해두면 필자가 아닌 다른 개발자는 ComponentPropsWithoutRef을 사용해야한다던가 Combine 타입을 사용할 때 타입 변수 T를 ElementType으로 제한해야한다던가 하는 귀찮은 부분을 생각하지 않고도 as 프로퍼티를 쉽고 빠르게 추가할 수 있을 것이다.