ファイルの頭に「import React from 'react';」を書く必要があるかについて (TS17004、TS2686エラー)

カテゴリ: 未分類 | タグ: , ,

Reactに関する書籍・web記事を見ていると、場合よってはjsx/tsxファイルの1行目にimport React from 'react'を書かなければならないという記述があります。

一方で、"この記述は古いバージョンの時の話で最近はそうではない"という記載もあります。

今回、ここの仕組みを理解するために確認してみました。

JSXのタグ

reactでは、<App />などjsxタグを記述することができますが、これはJavaScriptとしてvalidな形式ではありません。

ReactではjsxタグをJavaScriptの関数に変換する処理を挟む必要があります。

JSXタグの変換

jsxタグからJavaScriptの関数への変換ですが、React17.0以降では変換後としてJavaScriptに変換できる形式が増えています。

17.0ではReact.createElementの形式でしたが、17.0からはこれに加えてjsxの形式に変換することもできます。

React17.0より前

  • 変換前 (=あなたが書くReactのコード)
import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}
  • 変換後 (=Reactの仕組みで変換された後のコード)
    • 変換後のコードにReactが含まれていることに注意
import React from 'react';

function App() {
  return React.createElement('h1', null, 'Hello world');
}

React17.0以降

  • 変換前
function App() {
  return <h1>Hello World</h1>;
}
  • 変換後
    • 変換後のコードへimportを自動で追加してくれていることに注意
import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}

Webpackの定義

Webpackの定義ファイルであり`webpack.config.jsでは、以下のような形で*.tsxファイルに対する変換をts-loader`に行わせることを指定できます。

module.exports = {
    mode: 'development',
    devtool: 'inline-source-map',
    entry: './src/index.ts',
    module: {
        rules: [
            {
                test: /\.(js|jsx|ts|tsx)$/,
                exclude: /node_modules/,
                loader: 'ts-loader',
            }
        ]
    }
}

TypeScript

loaderにts-loaderを使った時、JSXタグをjsの関数へ変換する処理はTypeScriptが行います。

ということは、TypeScriptが(React.createElementではなく)、jsxに変換できるよう対応している必要がありますが、これはTypeScriptのバージョン4.1以降でサポートされています。

JSXのタグをReact.createElementとjsxのどちらの形式にするかは、tsconfig.jsonのcompilerOptionsの中にあるjsxで定義することができます。
(このドキュメントではこの設定項目を、これ以降compilerOptions.jsxと記載します)

定義の書き方

tsconfig.jsonのcompilerOptions.jsxですが、今回確認したい範囲でいうと以下の形式があります。

  • reactを指定する
{
  "compilerOptions": {
    "jsx": "react", 
  • react-jsxを指定する
{
  "compilerOptions": {
    "jsx": "react-jsx", 
  • 定義自体を書かない(コメントアウトなど)
{
  "compilerOptions": {
    // "jsx": "", 

compilerOptions.jsxの意味

compilerOptions.jsxの意味は、TypeScript: TSConfig Referenceに説明があります。

Controls how JSX constructs are emitted in JavaScript files. This only affects output of JS files that started in .tsx files.

react: Emit .js files with JSX changed to the equivalent React.createElement calls
react-jsx: Emit .js files with the JSX changed to _jsx calls
react-jsxdev: Emit .js files with the JSX changed to _jsx calls
preserve: Emit .jsx files with the JSX unchanged
react-native: Emit .js files with the JSX unchanged

書いてあるとおり、パラメータ値にraectを指定すると、React.createElementの形式に変換されます。

react-jsxだと、_jsxの形式に変換されます。

react-jsxdevも、_jsxの形式に変換されてますが、こちらは変換後のコードに元ファイルの番号などのデバッグ情報が追加されます。

import React from 'react';を書かなかった時の振る舞い

コードの頭にimport React from 'react';を書かずに、compilerOptions.jsx`に確認した値をセットしてコンパイルした時の出力を確認します。

  • reactを指定する

jsxのパラメータに"react"を指定した場合、TS17004エラーが出ます。

$ npm run dev

ERROR in App.tsx
./src/App.tsx 45:16-40
[tsl] ERROR in App.tsx(45,17)
      TS17004: Cannot use JSX unless the '--jsx' flag is provided.
  • react-jsxを指定する

この定義は正しいので、エラーにならなず正しくビルドできます。

  • 定義自体を書かない(コメントアウトなど)

jsxのパラメータを指定しない場合、TS2686エラーが出ます。

$ npm run dev

ERROR in App.tsx
./src/App.tsx 45:16-40
[tsl] ERROR in App.tsx(45,17)
     TS2686: 'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.

関連情報


Amazonでおトクに買い物する方法
AmazonチャージでポイントGET


Amazonは買いもの前にAmazonギフト券をチャージしてポイントをゲットしないと損!

こちらもおススメ

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です