일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- React #리액트 이벤트 주기 #리액트 이벤트
- html entities
- 빡킹독
- RateLimit
- 플로이드 #c++
- raect typescript #react #typescript #styled-component
- 백준 #적록색약
- React #Hook rules #Hook 규칙
- react fragment
- interceptors
- 얕은 복사 #깊은 복사 #shallow copy #deep copy
- 버블링 #갭쳐링 #이벤트 #JS
- JWT #토큰 #refreshToken #accessToken #Token #token #localStorage #sessionStorage
- React-Query
- DP #c++
- 코드스테이츠 #알고리즘 #그리디
- 백준 #직각삼각형
- useState #Hooks
- react
- donwstream #upstream #origin
- React #controlled component #비제어 컴포넌트 #제어 컴포넌트
- rate limit
- react #useCallback #react Hook
- 다익스트라 #파티 #백준
- React #effect hook #useEffect
- 이친수
- #useRef #언제 쓰는데?
- npm #not being able to find a file #npm install Error
- 노마드 코더 #타입스크립트 #typescript #class
- axios
- Today
- Total
꿈꾸는 개발자
JSX.IntrinsicElements에 대한 이해 본문
리액트에서 글이 많은 컴포넌트를 작성할 때 때로는 bold 형식의 글이 필요할 때가 있다. 하지만 매번 그럴 때 마다 <strong> 태그를 쓰기 귀찮아서, 뭔가 새로운 방법이 없을까 여러 코드를 탐험하던 중 흥미로운 코드를 찾았다.
import React from "react";
export function TranslateBold({ children, className, as = "p" }) {
const pattern = /(\*\*.*?\*\*)/;
const text = children;
const parts = text.split(pattern).filter((x) => x.length > 0);
const elements = parts.map((part, index) => {
if (part.match(pattern)) {
return <strong key={index}>{part.slice(2, -2)}</strong>;
} else {
return <span key={index}>{part}</span>;
}
});
return React.createElement(as, { className }, elements);
}
위 코드는 정규 표현식을 사용해서 일반 마크 다운에서 bold 처리를 해주는 것처럼 **hello**처럼 작성해주면 " ** ** " 사이에 있는 문장을 strong 태그 처리해준 후 그것을 새로운 React Element으로 반환하는 컴포넌트이다. 하지만 해당 코드는 JS로 짜여진 상태라 TS로 전환하기 위해선 props들의 타입을 정의해줄 필요가 있다. 처음에 단순히 전부 문자열로 처리하면 되겠지 단순하게 생각했었는데.. 추가적인 학습을 하던 중 JSX.IntrinsicElements이란 생소한 타입과 개념이 등장해서 정리를 하고자 한다.
keyof: 는 타입스크립트에서 객체 타입에서 객체의 키 값들을 숫자나 문자열 리터럴 유니언 타입을 생성한다.
type Point = { x: number; y: number };
type P = keyof Point;
위 에서 "p"의 타입은 "x" | "y" 로 지정된다
declare namespace JSX {
interface IntrinsicElements {
......중략.......
a: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>;
div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
img: React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>;
p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>;
li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>;
span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
......중략.......
}
}
위는 JSX namespace에 정의된 IntrinsicElements를 확인할 수 있다. 코드를 확인하면 알 수 있듯이 html 태그를 key:value 형식으로 묶어놓은 형태임을 알 수 있다. 따라서, keyof를 사용해서 들어올 html 태그를 유연하게 타입 정의를 해줄 수 있다.
타입 정의 결과
import React, { ReactElement } from "react";
interface TranslateBoldProps {
children: string;
className?: string;
as?: keyof JSX.IntrinsicElements;
}
export function TranslateBold({ children, className, as = "p" }: TranslateBoldProps): ReactElement {
const pattern = /(\*\*.*?\*\*)/;
const text = children;
const parts = text.split(pattern).filter((x) => x.length > 0);
const elements = parts.map((part, index) => {
if (part.match(pattern)) {
return <strong key={index}>{part.slice(2, -2)}</strong>;
} else {
return <span key={index}>{part}</span>;
}
});
물론 그냥 string으로 처리를 해도 문제가 없겠지만, 위 방식은 리터럴 타입 애너테이션으로 처리하는 방식이라 조금 더 네로잉 하는 방식이다. 타입 정의를 할 때 보다 구체적으로 네로잉을 할 수 있는 경우 그렇게 하는 게 더 적절하다고 생각한다..... 따라서, 위와 같이 타입을 정의했을 경우string타입과 달리 html 태그가 아니면 무조건 에러가 발생하게 된다.