개발새발

js 파일 생성하기 본문

Typescript

js 파일 생성하기

비숑주인 2025. 5. 30. 20:49

test.tsx를 JavaScript로 트랜스파일하기

아래 예시는 동일한 소스 test.tsx를 tsconfig.json 의 "jsx" 옵션만 바꿔가며 npx tsc 로 컴파일했을 때 어떤 JS 결과물이 생성되는지를 비교‧분석한 것이다. 모든 예시는 TypeScript 4.5 이상을 전제로 설명한다.

 

1. 기본 세팅

$ tree -L 1
.
├── tsconfig.json
└── test.tsx

 

test.tsx 안에는 일반적인 함수 컴포넌트가 들어 있다고 가정한다.

// test.tsx
import { useState, useCallback, useRef, useEffect } from 'react';

const Form = ({ children, onSubmit }) => (
  <form onSubmit={onSubmit}>{children}</form>
);

const WordRelay = () => {
  /* …중략… */
  return (
    <>
      <div>{word}</div>
      <Form onSubmit={onSubmitForm}>
        <input ref={inputEl} value={value} onChange={onChange} />
        <button>입력!</button>
      </Form>
      <div>{result}</div>
    </>
  );
};

export default WordRelay;

 

2. "jsx": "react-jsx" (새 런타임 · 기본 권장)

// tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx",          // 새 런타임
    "outDir": "dist"
  }
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");   // 자동 삽입
const react_1 = require("react");

const Form = ({ children, onSubmit }) => (
  (0, jsx_runtime_1.jsx)("form", { onSubmit, children })
);

const WordRelay = () => {
  const [word, setWord]   = (0, react_1.useState)('제로초');
  /* …중략… */
  return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [
    (0, jsx_runtime_1.jsx)("div", { children: word }),
    /* …생략… */
  ]});
};

 

  • 특징
    • react/jsx-runtime 가 한 줄 삽입되고, 모든 JSX는 jsx · jsxs 함수 호출로 변환된다.
    • import React from 'react' 가 더 이상 필요 없다. (컴포넌트 코드에서 React 식별자를 직접 쓰지 않는 한)
    • 번들러에 따라 tree-shaking 효율이 좋다.

3. "jsx": "react" (옛 런타임 · 호환 목적)

{
  "compilerOptions": {
    "jsx": "react",              //  old-school runtime
    "outDir": "dist"
  }
}
"use strict";
var __importStar = /* tslib 헬퍼 */ ;
Object.defineProperty(exports, "__esModule", { value: true });

const React = __importStar(require("react"));         // 전체 네임스페이스 가져옴

const Form = ({ children, onSubmit }) =>
  React.createElement("form", { onSubmit }, children);

const WordRelay = () => {
  const [word, setWord] = React.useState('제로초');
  /* …중략… */
  return React.createElement(React.Fragment, null,
    React.createElement("div", null, word),
    /* …생략… */
  );

 

  • 특징
    • 반드시 React 변수(네임스페이스)가 필요하므로 원본 소스에 import React from 'react' 구문을 직접 작성해야 한다.
    • 모든 JSX가 React.createElement 호출로 변환되어 구버전 도구 체인과 호환된다.

4. "jsx": "react-native" (네이티브 전용)

{
  "compilerOptions": {
    "jsx": "react-native",       // RN 전용
    "outDir": "dist"
  }
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = require("react");                     // 훅용 import만 남음

const Form = ({ children, onSubmit }) => (
  /* JSX 그대로 보존됨 */
  <form onSubmit={onSubmit}>{children}</form>
);

const WordRelay = () => {
  const [word, setWord] = (0, react_1.useState)('제로초');
  /* …중략… */
  return (
    <>
      <div>{word}</div>
      <Form onSubmit={onSubmitForm}>
        <input ref={inputEl} value={value} onChange={onChange} />
        <button>입력!</button>
      </Form>
      <div>{result}</div>
    </>
  );
};

 

  • 특징
    • JSX가 그대로 남는다. React Native 번들러(Metro)가 이후 단계에서 JS→네이티브 뷰로 변환하기 때문.
    • TypeScript는 훅 사용을 위해 import { useState … } from 'react' 만 유지한다.
    • 브라우저용 번들에는 바로 쓸 수 없는 코드이므로 RN 프로젝트 전용 설정이다.

5. 정리 — 어떤 옵션을 언제 쓸까?


jsx 값 주요 용 React import 필요 여부 출력 형태
react-jsx 권장: CRA·Vite 등 모던 웹 ❌ (자동) jsx/jsxs
react-jsxdev 개발 전용, Fast-Refresh + 에러 디버그 jsxDEV
react 레거시 도구 체인
(예: Webpack 4 + Babel 7 이전 preset-react)
React.createElement
preserve Babel 등 다른 트랜스파일러에게 JSX 변환을 위임 원본 유지 JSX 그대로
react-native React Native ❌ (React 객체 불필요) JSX 그대로
 

TIP

  1. react-jsx(react-jsxdev)로 옮기면 import React from 'react' 를 지워도 ESLint가 경고하지 않는다.
  2. Babel을 추가로 쓰지 않는 순수 tsc 빌드라면 react-jsx가 가장 간단·빠르다.
  3. 라이브러리(컴포넌트 패키지) 배포 시에는 소비자가 어떤 빌드 체인을 쓰는지 불확실하므로 소스는 JSX 그대로(preserve) 두고, 번들 단계에서 UMD·ESM 각각을 생성하는 전략을 권장한다.

결론

  • 웹 앱이라면 react-jsx 가 현재 표준이다.
  • 구형 레거시 환경 유지보수가 필요하면 react.
  • React Native 프로젝트는 react-native.
  • Babel / SWC 등 외부 트랜스파일러가 JSX를 처리한다면 preserve.

옵션 하나만 달리해도 결과 JS가 크게 달라지므로, 프로젝트 구성·배포 대상·도구 체인을 먼저 정리한 뒤 tsconfig.json 의 jsx 값을 선택해야 한다.

'Typescript' 카테고리의 다른 글

React 직접 타이핑 하기  (0) 2025.05.30
JSX 타입 이해하기  (0) 2025.05.24
React Hooks 분석하기  (0) 2025.05.24
React 타입 분석하기  (1) 2025.05.24
axios의 타입을 어떻게 찾았는지 이해하기  (0) 2025.05.17