首頁
學習紀錄
遊戲心得影視Life書單案件檔案
Side Projects委託作品與二創互動實驗場
Kurau
百百 BLOG
首頁
學習紀錄
遊戲心得影視Life書單案件檔案
Side Projects委託作品與二創互動實驗場
Kurau

Kurau Blog

「隨心而寫,真真假假,都是我」

一個記錄生活、輸出興趣的個人空間。
遊戲、影視、閱讀、學習……每一段體驗都值得留下文字。

頁面導覽

  • 學習紀錄
  • 遊戲心得
  • 影視Life
  • 書單
  • 委託作品與二創
  • Kurau
  • 合作邀請

找到我

歡迎來 Discord 找我聊天!

“曾經發生的事不可能忘記,只是暫時想不起來而已。”-《神隱少女》

© 2026 Kurau All rights reserved

程式語言

tsx 轉 jsx

By Kurau·2023-03-22·Updated 2026-05-09·5 分鐘閱讀

TSX 轉 JSX

TL;DR
用 npx tsc --jsx preserve 把 TS React 檔降級成 JS,用於需要 交付給非 TypeScript 環境 的場景。2026 年比較少需要,因為大部分 toolchain(Vite / Next.js / Rspack)都直接支援 TS。
主要參考
Stack Overflow — How do I convert TSX to JSX

何時需要轉

通常不需要 (現代環境都支援 TS)。但有時候會需要:

  • 交付給 只接受 JS 的舊系統
  • 把 TypeScript 寫的 範例 code 給只懂 JS 的學員 / 文件
  • 整合到 遺留 build pipeline 不能升級
  • 提交給 只接受 plain JS 的代碼審查 系統
大部分情況不需要
2026 年的現實:Webpack / Vite / Next.js / Bun / Deno 都直接吃 .tsx。除非真的有舊系統限制,否則別轉,維護 TS 比 JS 好太多。

安裝 TypeScript

npm install -g typescript

# 或本地用
npm install --save-dev typescript
bash

一條指令轉換

npx tsc --jsx preserve -t es2020 --outDir js --noEmit false
bash
Flag作用
--jsx preserve保留 <div> 語法,輸出 .jsx(不是 React.createElement)
-t es2020編譯目標 ES 版本(保留 import / async / await)
--outDir js輸出資料夾
--noEmit false強制輸出檔案(Expo 預設 noEmit:true,要 override)

執行後會在 js/ 資料夾看到:

js/
├── App.jsx
├── components/
│   ├── Header.jsx
│   └── Footer.jsx
└── utils.js                    // 純 .ts 檔變 .js

--jsx 三種模式

模式輸出用途
preserve.jsx(語法保留)交給其他 transpiler 處理
reactReact.createElement(...)舊 React
react-jsx_jsx(...)新 React 17+ runtime
react-jsxdev_jsxDEV(...)dev 模式(含 source 資訊)

想交付 JSX 給 React 環境用,選 preserve。讓接收端的 toolchain 處理 React runtime。


想保留更多 ES 特性

# 保留 ES2022 特性(top-level await / private fields)
npx tsc --jsx preserve -t es2022 --outDir js --noEmit false

# 保留 ESNext(最新)
npx tsc --jsx preserve -t esnext --outDir js --noEmit false

# 同時把 module 系統留 ESM
npx tsc --jsx preserve -t es2020 --module esnext --outDir js --noEmit false
bash

-t 越新 → 保留越多現代語法。但接收端要支援該版本。


完整 tsconfig 寫法(若要常用)

// tsconfig.export-jsx.json
{
  "compilerOptions": {
    "jsx": "preserve",
    "target": "es2020",
    "module": "esnext",
    "outDir": "./js",
    "rootDir": "./src",
    "noEmit": false,
    "skipLibCheck": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}
json
npx tsc -p tsconfig.export-jsx.json
bash

適合需要重複使用的轉換 pipeline。


Type 註解會怎樣?

--jsx preserve 還是會 strip 掉 type annotation:

// 原始 TSX
interface Props {
  name: string;
  age: number;
}

function Greet({ name, age }: Props) {
  return <h1>{name} is {age}</h1>;
}
typescript
// 輸出 JSX
function Greet({ name, age }) {
    return <h1>{name} is {age}</h1>;
}
// interface Props 直接消失
jsx

tsc 永遠 strip types,沒辦法把 type 留在 JSX 裡。


替代:用 --declaration 同時生 .d.ts

如果你還想保留 type 給未來用:

npx tsc --jsx preserve --declaration -t es2020 --outDir js
bash

輸出:

js/
├── Greet.jsx           // 純 JS
└── Greet.d.ts          // type 宣告

有 .d.ts 的話,以後合作的 TS 開發者還能用 — 變相保留 type 資訊。


實際使用注意

1. JSX 內嵌的 type assertion 會留下
const x = <div>{value as string}</div>;
tsx

as string 在 --jsx preserve 模式下保留在 JSX 中,輸出 .jsx 仍含 TypeScript 語法。 解法:用 --jsx react-jsx 把 JSX 也轉掉(輸出 .js),或先手動清掉 type assertion。

2. import 的 .tsx 副檔名
import Header from './Header';   // OK
import Header from './Header.tsx';   // ❌ 輸出 .jsx 後路徑不對
typescript

寫 import 時 別寫副檔名,讓 tooling 處理。

3. 三斜線指令保留
/// <reference types="node" />
typescript

這類 TS 特有指令在 .jsx 中沒意義,但不會被自動移除。手動刪。


反方向:JSX 轉 TSX

想把舊 JSX 升級成 TSX 反而比較常見(個人 / 團隊 migration):

# 改副檔名
mv App.jsx App.tsx

# 安裝 TS + React types
npm install --save-dev typescript @types/react @types/react-dom

# 加 tsconfig
npx tsc --init --jsx preserve --target es2020
bash

然後 逐檔加 type,先 any 後修。詳見 TypeScript Migration 官方指南。

目錄

    ◆ 相關文章

    • JavaScript 浮點數問題

      2026-05-09
    • Python Self learning

      2026-05-09
    • Java SE 6 技術手冊

      2026-05-09
    • Class-Based & Prototype-Based

      Class-Based & Prototype-Based

      2026-05-09
    ← 上一篇上一步 下一步 與 清除的邏輯規則下一篇 →Type 和 Interface的差別

    ◆ 關於作者

    Kurau

    個人寫作 / 創作的 SoT,記錄遊戲、影視、學習與生活。

    更多 Kurau 的文章