Emotion 初期設定完全ガイド:Babel/SWC/型定義/型拡張のベストプラクティス

Emotion は CSS-in-JS のライブラリとして、React プロジェクトで広く利用されていますね。しかし、いざ導入しようとすると「Babel と SWC のどちらを選ぶべき?」「型定義はどう設定するの?」「型拡張って必要なの?」といった疑問が次々と湧いてくるのではないでしょうか。
本記事では、Emotion の初期設定における選択肢を整理し、それぞれの設定方法とベストプラクティスを段階的に解説します。最後まで読めば、あなたのプロジェクトに最適な Emotion 環境が構築できるようになるでしょう。
背景
CSS-in-JS としての Emotion の位置づけ
CSS-in-JS は、JavaScript の中で CSS を記述できる手法です。従来の CSS ファイル分割と比べて、コンポーネントとスタイルを密結合できるため、保守性や再利用性が向上します。
Emotion は styled-components と並ぶ人気の CSS-in-JS ライブラリで、以下の特徴を持ちますね。
- 高いパフォーマンス: ランタイムでの最適化が優れている
- 柔軟な記法: css prop と styled API の両方をサポート
- TypeScript サポート: 型安全な開発が可能
- 小さいバンドルサイズ: 必要な機能だけを含められる
トランスパイラの選択肢
Emotion を使用する際、JSX の変換処理を担うトランスパイラの選択が重要になります。主な選択肢は以下の 2 つです。
mermaidflowchart TD
source["JSX + Emotion コード"] --> choice{"トランスパイラ<br/>選択"}
choice -->|従来| babel["Babel + @emotion/babel-plugin"]
choice -->|次世代| swc["SWC + @swc/plugin-emotion"]
babel --> result1["変換後の JavaScript"]
swc --> result2["変換後の JavaScript"]
result1 --> runtime["ブラウザで実行"]
result2 --> runtime
図で理解できる要点:
- Emotion コードは必ずトランスパイラを経由して変換される
- Babel と SWC はどちらも同じ結果を生成するが、速度が異なる
- 最終的にはブラウザで実行可能な JavaScript になる
それぞれの特徴を表にまとめました。
# | トランスパイラ | ビルド速度 | 成熟度 | プラグインエコシステム | 推奨ケース |
---|---|---|---|---|---|
1 | Babel | ★★☆ | ★★★ | ★★★ | 多数の Babel プラグインを使う既存プロジェクト |
2 | SWC | ★★★ | ★★☆ | ★★☆ | ビルド速度を重視する新規プロジェクト |
型定義と型拡張の必要性
TypeScript で Emotion を使用する場合、以下の 2 つの型設定が必要です。
- 基本の型定義: Emotion の API に対する型情報
- 型拡張(Theme): カスタムテーマの型安全性を確保
型拡張を行わないと、theme オブジェクトにアクセスする際に型エラーが発生したり、補完が効かなくなったりします。
課題
Babel と SWC の選択基準が不明確
初学者にとって、Babel と SWC のどちらを選ぶべきか判断するのは困難ですね。公式ドキュメントでは両方の選択肢が提示されていますが、具体的な選択基準が明示されていません。
また、Next.js や Vite など、フレームワークによってデフォルトのトランスパイラが異なるため、さらに混乱を招きます。
css prop 使用時の JSX Pragma 設定
Emotion の css prop を使用するには、JSX の変換方法を Emotion 専用のものに切り替える必要があります。これを「JSX Pragma」の設定と呼びますが、設定方法が複数あり、どれを選ぶべきか迷うポイントです。
mermaidflowchart LR
jsx["JSX コード<br/>(css prop 付き)"] --> pragma{"JSX Pragma<br/>設定方法"}
pragma -->|方法1| comment["ファイルごとの<br/>コメント指定"]
pragma -->|方法2| tsconfig["tsconfig.json<br/>での一括設定"]
pragma -->|方法3| plugin["Babel/SWC<br/>プラグイン設定"]
comment --> transform["Emotion の<br/>JSX 変換"]
tsconfig --> transform
plugin --> transform
図で理解できる要点:
- css prop を使うには JSX 変換の指定が必須
- 3 つの設定方法があり、プロジェクトに応じて選択する
- どの方法も最終的には Emotion の JSX 変換を実行する
Theme の型拡張が複雑
Emotion で独自のテーマを定義する場合、TypeScript の Module Augmentation(モジュール拡張)を使う必要があります。しかし、以下の問題が発生しやすいですね。
- 拡張ファイルの配置場所: どこに置けば認識されるのか
- import の有無: import すべきか、しなくても動くのか
- 複数テーマの管理: ライトモードとダークモードで型をどう扱うか
これらの疑問が解消されないと、型エラーに悩まされ続けることになります。
パッケージの依存関係が分かりにくい
Emotion には複数のパッケージがあり、どれをインストールすべきか迷います。
@emotion/react
: コアパッケージ@emotion/styled
: styled API 用@emotion/babel-plugin
: Babel 用プラグイン@swc/plugin-emotion
: SWC 用プラグイン
特に、css prop だけ使う場合と styled API も使う場合で、必要なパッケージが異なる点が混乱を招きますね。
解決策
1. トランスパイラ選択のフローチャート
以下のフローチャートに従って、プロジェクトに適したトランスパイラを選択しましょう。
mermaidflowchart TD
start["Emotion を導入"] --> q1{"Next.js 12+<br/>を使用?"}
q1 -->|はい| swc_default["SWC を選択<br/>(デフォルト)"]
q1 -->|いいえ| q2{"既存の Babel<br/>プラグインが多数?"}
q2 -->|はい| babel_choice["Babel を選択"]
q2 -->|いいえ| q3{"ビルド速度を<br/>最優先?"}
q3 -->|はい| swc_choice["SWC を選択"]
q3 -->|いいえ| babel_choice
推奨判断基準:
# | 条件 | 推奨トランスパイラ | 理由 |
---|---|---|---|
1 | Next.js 12 以降を使用 | SWC | Next.js のデフォルト、追加設定が最小 |
2 | 既存 Babel プラグインが 5 つ以上 | Babel | プラグインエコシステムが豊富 |
3 | 新規プロジェクト | SWC | ビルド速度が最大 20 倍高速 |
4 | CRA(Create React App) | Babel | CRA のデフォルト構成と相性が良い |
2. Babel 設定パターン
Babel を選択した場合の完全な設定手順です。
パッケージのインストール
まず必要なパッケージをインストールします。css prop と styled API の両方を使う想定です。
bashyarn add @emotion/react @emotion/styled
開発用の Babel プラグインを追加しましょう。
bashyarn add -D @emotion/babel-plugin
.babelrc の設定
プロジェクトルートに .babelrc
ファイルを作成します。
json{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript"
]
}
Emotion のプラグインを追加します。この設定により css prop が自動的に認識されるようになります。
json{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript"
],
"plugins": ["@emotion/babel-plugin"]
}
tsconfig.json の設定(TypeScript の場合)
TypeScript を使用する場合、JSX の変換設定を追加します。
json{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
}
}
jsxImportSource
を設定することで、ファイルごとに /** @jsxImportSource @emotion/react */
を書く必要がなくなります。
3. SWC 設定パターン
SWC を選択した場合の設定手順です。Next.js 12 以降を想定しています。
パッケージのインストール
Emotion のコアパッケージをインストールします。
bashyarn add @emotion/react @emotion/styled
SWC 用のプラグインを追加しましょう。
bashyarn add -D @swc/plugin-emotion
next.config.js の設定
Next.js の設定ファイルに SWC プラグインを追加します。
javascript/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};
module.exports = nextConfig;
SWC のコンパイラオプションを追加します。
javascript/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
compiler: {
emotion: true,
},
};
module.exports = nextConfig;
詳細なオプションを設定する場合は、以下のようにオブジェクト形式で記述できます。
javascript/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
compiler: {
emotion: {
// 本番環境でソースマップを有効化
sourceMap: true,
// 開発時に自動でラベルを付与
autoLabel: 'dev-only',
// ラベルのフォーマット指定
labelFormat: '[local]',
},
},
};
module.exports = nextConfig;
tsconfig.json の設定
TypeScript の設定は Babel の場合と同じです。
json{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
}
}
4. Theme の型拡張パターン
独自のテーマを型安全に使用するための設定です。
テーマオブジェクトの定義
まず、テーマの実体を定義します。src/styles/theme.ts
に配置しましょう。
typescript// カラーパレットの定義
const colors = {
primary: '#3f51b5',
secondary: '#f50057',
background: '#ffffff',
text: '#333333',
};
スペーシングやタイポグラフィも追加します。
typescript// カラーパレットの定義
const colors = {
primary: '#3f51b5',
secondary: '#f50057',
background: '#ffffff',
text: '#333333',
};
// スペーシングシステム
const spacing = {
xs: '4px',
sm: '8px',
md: '16px',
lg: '24px',
xl: '32px',
};
テーマオブジェクトをエクスポートします。
typescript// カラーパレットの定義
const colors = {
primary: '#3f51b5',
secondary: '#f50057',
background: '#ffffff',
text: '#333333',
};
// スペーシングシステム
const spacing = {
xs: '4px',
sm: '8px',
md: '16px',
lg: '24px',
xl: '32px',
};
// テーマオブジェクトの統合
export const theme = {
colors,
spacing,
};
// テーマの型を取得
export type Theme = typeof theme;
型拡張ファイルの作成
src/types/emotion.d.ts
ファイルを作成して、Emotion の Theme 型を拡張します。
typescript// @emotion/react モジュールを拡張
import '@emotion/react';
独自の Theme 型をインポートして、モジュール拡張を行います。
typescript// @emotion/react モジュールを拡張
import '@emotion/react';
import { Theme as CustomTheme } from '../styles/theme';
declare module で型を上書きしましょう。
typescript// @emotion/react モジュールを拡張
import '@emotion/react';
import { Theme as CustomTheme } from '../styles/theme';
declare module '@emotion/react' {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Theme extends CustomTheme {}
}
この設定により、theme.colors.primary
などの補完が効くようになります。
ThemeProvider での使用
アプリケーションのルートで ThemeProvider を設定します。src/pages/_app.tsx
の例です。
typescriptimport { ThemeProvider } from '@emotion/react';
import type { AppProps } from 'next/app';
import { theme } from '../styles/theme';
ThemeProvider でアプリケーション全体をラップします。
typescriptimport { ThemeProvider } from '@emotion/react';
import type { AppProps } from 'next/app';
import { theme } from '../styles/theme';
export default function App({
Component,
pageProps,
}: AppProps) {
return (
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
);
}
5. 複数テーマの管理パターン
ライトモードとダークモードを切り替える場合の設計です。
テーマ定義の分離
共通の色定義と、モードごとの色を分けて管理します。src/styles/themes.ts
を作成しましょう。
typescript// 共通のカラーパレット
const commonColors = {
primary: '#3f51b5',
secondary: '#f50057',
success: '#4caf50',
error: '#f44336',
};
ライトモード用のテーマを定義します。
typescript// 共通のカラーパレット
const commonColors = {
primary: '#3f51b5',
secondary: '#f50057',
success: '#4caf50',
error: '#f44336',
};
// ライトモードテーマ
export const lightTheme = {
...commonColors,
background: '#ffffff',
text: '#333333',
border: '#e0e0e0',
};
ダークモード用のテーマを追加します。
typescript// 共通のカラーパレット
const commonColors = {
primary: '#3f51b5',
secondary: '#f50057',
success: '#4caf50',
error: '#f44336',
};
// ライトモードテーマ
export const lightTheme = {
...commonColors,
background: '#ffffff',
text: '#333333',
border: '#e0e0e0',
};
// ダークモードテーマ
export const darkTheme = {
...commonColors,
background: '#121212',
text: '#ffffff',
border: '#424242',
};
// 型定義(どちらのテーマも同じ構造)
export type Theme = typeof lightTheme;
型拡張の更新
先ほど作成した src/types/emotion.d.ts
を更新します。
typescriptimport '@emotion/react';
import { Theme as CustomTheme } from '../styles/themes';
declare module '@emotion/react' {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Theme extends CustomTheme {}
}
テーマ切り替えロジック
状態管理でテーマを切り替える例です。src/contexts/ThemeContext.tsx
を作成しましょう。
typescriptimport { createContext, useState, ReactNode } from 'react';
import { ThemeProvider as EmotionThemeProvider } from '@emotion/react';
import { lightTheme, darkTheme } from '../styles/themes';
// コンテキストの型定義
type ThemeContextType = {
isDark: boolean;
toggleTheme: () => void;
};
コンテキストを作成します。
typescriptimport { createContext, useState, ReactNode } from 'react';
import { ThemeProvider as EmotionThemeProvider } from '@emotion/react';
import { lightTheme, darkTheme } from '../styles/themes';
// コンテキストの型定義
type ThemeContextType = {
isDark: boolean;
toggleTheme: () => void;
};
export const ThemeContext = createContext<ThemeContextType>(
{
isDark: false,
toggleTheme: () => {},
}
);
Provider コンポーネントを実装します。
typescriptexport const ThemeProvider = ({
children,
}: {
children: ReactNode;
}) => {
const [isDark, setIsDark] = useState(false);
// テーマ切り替え関数
const toggleTheme = () => {
setIsDark((prev) => !prev);
};
// 現在のテーマを選択
const currentTheme = isDark ? darkTheme : lightTheme;
return (
<ThemeContext.Provider value={{ isDark, toggleTheme }}>
<EmotionThemeProvider theme={currentTheme}>
{children}
</EmotionThemeProvider>
</ThemeContext.Provider>
);
};
6. パッケージ構成の一覧表
使用するパッケージを一覧で整理します。
# | パッケージ名 | 用途 | css prop のみ | styled API も使用 | Babel 使用時 | SWC 使用時 |
---|---|---|---|---|---|---|
1 | @emotion/react | コアパッケージ | ★ 必須 | ★ 必須 | ★ 必須 | ★ 必須 |
2 | @emotion/styled | styled API 用 | 不要 | ★ 必須 | ★ 必須 | ★ 必須 |
3 | @emotion/babel-plugin | Babel プラグイン | 不要 | 不要 | ★ 必須 | 不要 |
4 | @swc/plugin-emotion | SWC プラグイン | 不要 | 不要 | 不要 | ★ 必須 |
この表を参考に、プロジェクトに必要なパッケージだけをインストールしましょう。
具体例
実践例 1: Next.js + SWC + Theme の完全セットアップ
新規 Next.js プロジェクトで Emotion をセットアップする完全な手順です。
プロジェクトの初期化
Next.js プロジェクトを作成します。
bashyarn create next-app my-emotion-app --typescript
cd my-emotion-app
パッケージのインストール
Emotion の必要なパッケージをインストールしましょう。
bashyarn add @emotion/react @emotion/styled
yarn add -D @swc/plugin-emotion
ディレクトリ構成
以下の構成でファイルを作成します。
cssmy-emotion-app/
├── src/
│ ├── pages/
│ │ └── _app.tsx
│ ├── styles/
│ │ └── theme.ts
│ ├── types/
│ │ └── emotion.d.ts
│ └── components/
│ └── Button.tsx
├── next.config.js
└── tsconfig.json
next.config.js の設定
SWC で Emotion を有効化します。
javascript/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
compiler: {
emotion: {
sourceMap: true,
autoLabel: 'dev-only',
labelFormat: '[local]',
},
},
};
module.exports = nextConfig;
tsconfig.json の更新
JSX の import source を設定します。既存の compilerOptions
に追加しましょう。
json{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
}
}
テーマの定義
src/styles/theme.ts
を作成します。
typescriptexport const theme = {
colors: {
primary: '#0070f3',
secondary: '#ff4081',
background: '#ffffff',
text: '#000000',
gray: {
100: '#f5f5f5',
200: '#eeeeee',
300: '#e0e0e0',
},
},
spacing: {
xs: '4px',
sm: '8px',
md: '16px',
lg: '24px',
xl: '32px',
},
breakpoints: {
mobile: '480px',
tablet: '768px',
desktop: '1024px',
},
};
export type Theme = typeof theme;
型拡張の設定
src/types/emotion.d.ts
を作成します。
typescriptimport '@emotion/react';
import { Theme as CustomTheme } from '../styles/theme';
declare module '@emotion/react' {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Theme extends CustomTheme {}
}
_app.tsx の設定
src/pages/_app.tsx
で ThemeProvider を設定します。
typescriptimport { ThemeProvider } from '@emotion/react';
import type { AppProps } from 'next/app';
import { theme } from '../styles/theme';
export default function App({
Component,
pageProps,
}: AppProps) {
return (
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
);
}
コンポーネントでの使用例
src/components/Button.tsx
を作成して、theme を使用します。
typescriptimport styled from '@emotion/styled';
export const Button = styled.button`
padding: ${({ theme }) => theme.spacing.md};
background-color: ${({ theme }) => theme.colors.primary};
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
`;
css prop を使った別の実装例です。
typescript/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import { useTheme } from '@emotion/react';
export const CssPropButton = () => {
const theme = useTheme();
return (
<button
css={css`
padding: ${theme.spacing.md};
background-color: ${theme.colors.primary};
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
`}
>
Click me
</button>
);
};
この設定により、型補完が効いた状態で Emotion を使用できますね。
実践例 2: CRA + Babel + 複数テーマの実装
Create React App で Babel を使う場合の例です。
プロジェクトの初期化
CRA でプロジェクトを作成します。
bashyarn create react-app my-emotion-app --template typescript
cd my-emotion-app
パッケージのインストール
必要なパッケージをインストールしましょう。
bashyarn add @emotion/react @emotion/styled
yarn add -D @emotion/babel-plugin
Babel 設定の追加
CRA では .babelrc
が隠れているため、package.json
に設定を追加します。
json{
"babel": {
"presets": ["react-app"],
"plugins": ["@emotion/babel-plugin"]
}
}
別の方法として、craco
を使って設定を上書きすることもできます。
bashyarn add -D @craco/craco
craco.config.js
を作成して、Babel プラグインを追加します。
javascriptmodule.exports = {
babel: {
plugins: ['@emotion/babel-plugin'],
},
};
package.json
のスクリプトを更新しましょう。
json{
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test"
}
}
複数テーマの定義
src/styles/themes.ts
を作成します。
typescriptconst baseTheme = {
spacing: {
xs: '4px',
sm: '8px',
md: '16px',
lg: '24px',
xl: '32px',
},
borderRadius: {
sm: '4px',
md: '8px',
lg: '12px',
},
};
export const lightTheme = {
...baseTheme,
colors: {
primary: '#1976d2',
secondary: '#dc004e',
background: '#ffffff',
surface: '#f5f5f5',
text: '#212121',
textSecondary: '#757575',
},
};
export const darkTheme = {
...baseTheme,
colors: {
primary: '#90caf9',
secondary: '#f48fb1',
background: '#121212',
surface: '#1e1e1e',
text: '#ffffff',
textSecondary: '#b0b0b0',
},
};
export type Theme = typeof lightTheme;
テーマコンテキストの実装
src/contexts/ThemeContext.tsx
を作成します。
typescriptimport {
createContext,
useContext,
useState,
ReactNode,
useEffect,
} from 'react';
import { ThemeProvider as EmotionThemeProvider } from '@emotion/react';
import { lightTheme, darkTheme } from '../styles/themes';
type ThemeMode = 'light' | 'dark';
type ThemeContextType = {
mode: ThemeMode;
toggleTheme: () => void;
};
コンテキストとフックを定義します。
typescriptconst ThemeContext = createContext<
ThemeContextType | undefined
>(undefined);
export const useThemeContext = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error(
'useThemeContext must be used within ThemeProvider'
);
}
return context;
};
Provider コンポーネントを実装しましょう。
typescriptexport const ThemeProvider = ({
children,
}: {
children: ReactNode;
}) => {
// localStorage からテーマを復元
const [mode, setMode] = useState<ThemeMode>(() => {
const saved = localStorage.getItem('theme-mode');
return (saved as ThemeMode) || 'light';
});
// テーマ切り替え
const toggleTheme = () => {
setMode((prev) =>
prev === 'light' ? 'dark' : 'light'
);
};
// localStorage に保存
useEffect(() => {
localStorage.setItem('theme-mode', mode);
}, [mode]);
const currentTheme =
mode === 'light' ? lightTheme : darkTheme;
return (
<ThemeContext.Provider value={{ mode, toggleTheme }}>
<EmotionThemeProvider theme={currentTheme}>
{children}
</EmotionThemeProvider>
</ThemeContext.Provider>
);
};
App.tsx での使用
src/App.tsx
でテーマを適用します。
typescriptimport { ThemeProvider } from './contexts/ThemeContext';
import { MainContent } from './components/MainContent';
function App() {
return (
<ThemeProvider>
<MainContent />
</ThemeProvider>
);
}
export default App;
テーマ切り替えボタンの実装
src/components/ThemeToggle.tsx
を作成します。
typescriptimport styled from '@emotion/styled';
import { useThemeContext } from '../contexts/ThemeContext';
const ToggleButton = styled.button`
padding: ${({ theme }) => theme.spacing.md};
background-color: ${({ theme }) => theme.colors.primary};
color: ${({ theme }) => theme.colors.text};
border: none;
border-radius: ${({ theme }) => theme.borderRadius.md};
cursor: pointer;
font-size: 16px;
transition: opacity 0.2s;
&:hover {
opacity: 0.8;
}
`;
export const ThemeToggle = () => {
const { mode, toggleTheme } = useThemeContext();
return (
<ToggleButton onClick={toggleTheme}>
{mode === 'light'
? '🌙 ダークモード'
: '☀️ ライトモード'}
</ToggleButton>
);
};
グローバルスタイルの適用
src/components/GlobalStyles.tsx
を作成して、全体のスタイルを定義します。
typescriptimport { Global, css, useTheme } from '@emotion/react';
export const GlobalStyles = () => {
const theme = useTheme();
return (
<Global
styles={css`
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont,
'Segoe UI', 'Roboto', sans-serif;
background-color: ${theme.colors.background};
color: ${theme.colors.text};
transition: background-color 0.3s, color 0.3s;
}
`}
/>
);
};
src/components/MainContent.tsx
でグローバルスタイルを読み込みます。
typescriptimport { GlobalStyles } from './GlobalStyles';
import { ThemeToggle } from './ThemeToggle';
export const MainContent = () => {
return (
<>
<GlobalStyles />
<div>
<h1>Emotion Theme Example</h1>
<ThemeToggle />
</div>
</>
);
};
この実装により、テーマの切り替えが localStorage に保存され、リロード後も保持されます。
実践例 3: トラブルシューティング
Emotion の初期設定でよく遭遇するエラーと解決方法をまとめました。
エラー 1: Property 'css' does not exist on type 'DetailedHTMLProps'
エラーコード: TypeScript Error TS2322
エラーメッセージ:
bashProperty 'css' does not exist on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'.
発生条件:
- tsconfig.json で
jsxImportSource
が設定されていない - ファイルの先頭に JSX Pragma が記載されていない
解決方法:
tsconfig.json に以下を追加します。
json{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
}
}
または、ファイルごとに以下のコメントを追加しましょう。
typescript/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
エラー 2: Module '"@emotion/react"' has no exported member 'Theme'
エラーコード: TypeScript Error TS2305
エラーメッセージ:
sqlModule '"@emotion/react"' has no exported member 'Theme'.
発生条件:
- 型拡張ファイル(emotion.d.ts)が認識されていない
- tsconfig.json の include に型定義ファイルが含まれていない
解決方法:
tsconfig.json の include を確認します。
json{
"include": ["src/**/*", "src/types/**/*.d.ts"]
}
型拡張ファイルのパスが正しいか確認しましょう。
typescript// src/types/emotion.d.ts
import '@emotion/react';
import { Theme as CustomTheme } from '../styles/theme';
declare module '@emotion/react' {
export interface Theme extends CustomTheme {}
}
IDE を再起動するか、TypeScript サーバーを再起動します。VS Code の場合は以下のコマンドを実行してください。
arduinoCmd + Shift + P → "TypeScript: Restart TS Server"
エラー 3: Cannot find module '@swc/plugin-emotion'
エラーコード: Module Not Found Error
エラーメッセージ:
arduinoError: Cannot find module '@swc/plugin-emotion'
発生条件:
- next.config.js で SWC プラグインを指定しているが、パッケージがインストールされていない
解決方法:
パッケージをインストールします。
bashyarn add -D @swc/plugin-emotion
Next.js 12.2 以降では、プラグインなしでも動作する場合があります。その場合は以下の設定で十分です。
javascriptmodule.exports = {
compiler: {
emotion: true,
},
};
エラー 4: Theme の補完が効かない
症状:
theme.colors.primary
などの補完が出ない- エラーは出ないが、型チェックが機能していない
原因:
- 型拡張ファイルが import されていない
- 循環参照が発生している
解決方法:
型拡張ファイルを確認します。import 文が正しく記載されているか確認しましょう。
typescriptimport '@emotion/react';
import { Theme as CustomTheme } from '../styles/theme';
declare module '@emotion/react' {
export interface Theme extends CustomTheme {}
}
_app.tsx などで型拡張ファイルを明示的に import します。
typescriptimport '../types/emotion.d.ts'; // 明示的に読み込む
import { ThemeProvider } from '@emotion/react';
TypeScript のバージョンが古い場合は更新しましょう。
bashyarn add -D typescript@latest
まとめ
Emotion の初期設定は、トランスパイラの選択、JSX Pragma の設定、型定義の拡張という 3 つのステップで構成されます。それぞれのステップで複数の選択肢があり、プロジェクトの特性に応じて最適な組み合わせを選ぶことが重要です。
設定の選択基準
# | 項目 | 新規プロジェクト | 既存プロジェクト(Babel) | Next.js 12+ | CRA |
---|---|---|---|---|---|
1 | トランスパイラ | SWC | Babel | SWC | Babel |
2 | パッケージ | @emotion/react + @swc/plugin-emotion | @emotion/react + @emotion/babel-plugin | @emotion/react | @emotion/react |
3 | 設定ファイル | next.config.js | .babelrc | next.config.js | craco.config.js |
4 | TypeScript 設定 | jsxImportSource | jsxImportSource | jsxImportSource | jsxImportSource |
ベストプラクティス
- トランスパイラの選択: Next.js 12 以降では SWC、CRA や既存の Babel 環境では Babel を選択しましょう
- 型拡張の実装: 独自テーマを使う場合は必ず emotion.d.ts で型拡張を行います
- パッケージの最小化: css prop だけ使う場合は @emotion/styled は不要です
- 複数テーマの管理: テーマごとに別オブジェクトを定義し、Context で切り替えます
- 型補完の確保: tsconfig.json の jsxImportSource 設定を忘れずに行いましょう
実装のチェックリスト
設定が正しく完了しているか、以下のチェックリストで確認してください。
- @emotion/react がインストールされている
- トランスパイラに応じたプラグインがインストールされている
- tsconfig.json で jsxImportSource が設定されている
- 型拡張ファイル(emotion.d.ts)が作成されている
- ThemeProvider がアプリケーションルートに配置されている
- theme オブジェクトで型補完が効いている
- css prop が TypeScript エラーなく使用できている
これらのステップを踏むことで、型安全で保守性の高い Emotion 環境を構築できます。初期設定の選択肢に迷ったときは、本記事のフローチャートや一覧表を参考にして、プロジェクトに最適な構成を見つけてくださいね。
関連リンク
- article
Emotion 初期設定完全ガイド:Babel/SWC/型定義/型拡張のベストプラクティス
- article
Motion(旧 Framer Motion) vs CSS Transition/WAAPI:可読性・制御性・性能を実測比較
- article
Emotion vs styled-components vs Stitches 徹底比較:DX/SSR/パフォーマンス実測
- article
Emotion 完全理解 2025:CSS-in-JS の強み・弱み・採用判断を徹底解説
- article
Emotion の Server API で本格 SSR を実現
- article
Emotion で SVG アイコンや画像にスタイルを適用する
- article
NotebookLM とは?Google 製 AI ノートの仕組みとできることを 3 分で解説
- article
Mermaid 図面の命名規約:ノード ID・エッジ記法・クラス名の統一ガイド
- article
Emotion 初期設定完全ガイド:Babel/SWC/型定義/型拡張のベストプラクティス
- article
Electron セキュリティ設定チートシート:webPreferences/CSP/許可リスト早見表
- article
MCP サーバー とは?Model Context Protocol の基礎・仕組み・活用メリットを徹底解説
- article
Yarn とは?npm・pnpm と何が違うのかを 3 分で理解【決定版】
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来