<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>フロントエンド ‣ てんハロ｜未経験エンジニアのIT学習ログ</title>
	<atom:link href="https://it-bokenki.com/category/frontend/feed/" rel="self" type="application/rss+xml" />
	<link>https://it-bokenki.com</link>
	<description>Hello Worldから、今日も生きてる</description>
	<lastBuildDate>Tue, 22 Jul 2025 12:15:49 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://it-bokenki.com/wp-content/uploads/2025/06/cropped-ブログ　アイコン-32x32.png</url>
	<title>フロントエンド ‣ てんハロ｜未経験エンジニアのIT学習ログ</title>
	<link>https://it-bokenki.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>as const って何？「値＝型」にできるTypeScriptの型ガード術</title>
		<link>https://it-bokenki.com/2025/07/20/as-const/</link>
					<comments>https://it-bokenki.com/2025/07/20/as-const/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Sun, 20 Jul 2025 07:06:16 +0000</pubDate>
				<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=5021</guid>

					<description><![CDATA[<p>未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 TypeScript定数を定義して、あとからそのまま型にも使いたいとき。 「書いた値を使って型をつくったはずなのに、strin [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/20/as-const/">as const って何？「値＝型」にできるTypeScriptの型ガード術</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img fetchpriority="high" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>TypeScript定数を定義して、あとからそのまま型にも使いたいとき。</p>



<p>「書いた値を使って型をつくったはずなのに、string型になってる…」<br>「え、これユニオン型じゃないの？なんで？」<br>って何回もなった。</p>



<p>毎回型を別で書き直すの、地味に面倒くさいしミスも増える。<br>そんなときに知った <code>as const</code>、たった一言で「値＝型」になって、ほんとに楽になった。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">as constとは？</span></h2>



<p><code>as const</code> は TypeScript の構文で、<strong>値を“そのまま”の形で型として固定する</strong>ための書き方です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const COLORS = &#91;"red", "blue", "green"&#93;;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>このとき、<code>COLORS</code> の型は <code>string[]</code> になります。<br>つまり、 <code>"yellow"</code> など本来想定していない値も通ってしまう可能性があります。</p>



<p>しかし <code>as const</code> を使うと</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const COLORS = &#91;"red", "blue", "green"&#93; as const;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span></code></pre></div>



<p>これだけで、型はこうなります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>readonly &#91;"red", "blue", "green"&#93;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">readonly</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span></span></code></pre></div>



<p>中身の <code>"red" | "blue" | "green"</code> を型として使えるようになります。この状態になると、「この配列の中には、決まった値しか入っていない」と型で表現できるようになります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">「型」ってそもそも何？</span></h2>



<p>TypeScriptでは、以下のような<strong>基本的な型（プリミティブ型）</strong>があります。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>型名</th><th>意味</th><th>例</th></tr></thead><tbody><tr><td><code>string</code></td><td>文字列</td><td><code>"hello"</code></td></tr><tr><td><code>number</code></td><td>数値</td><td><code>42</code></td></tr><tr><td><code>boolean</code></td><td>真偽値</td><td><code>true</code> / <code>false</code></td></tr><tr><td><code>string[]</code></td><td>文字列の配列</td><td><code>["a", "b"]</code></td></tr></tbody></table></figure>



<p>多くの人は「型＝stringやnumberのこと」と思っているはずです。<br>でも、TypeScriptには他にも重要な型の考え方があります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc4">リテラル型とユニオン型の違い</span></h3>



<p><strong>リテラル型</strong>：特定の値だけを許す型</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const color: "red" = "red"; // "red" だけOK</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">color</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// &quot;red&quot; だけOK</span></span></code></pre></div>



<p><strong>ユニオン型</strong>：複数の値の中からどれか1つを許す型</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>type Color = "red" | "blue" | "green";</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Color </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>つまり、リテラル型は1つだけOK、ユニオン型は&#8221;いくつかから1つ選ぶ&#8221;感じです。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc5">配列で使う as const</span></h2>



<p>たとえば、次のようなコードがあります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const COLORS = &#91;"red", "blue", "green"&#93; as const;
type Color = typeof COLORS&#91;number&#93;;
// → "red" | "blue" | "green"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Color </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// → &quot;red&quot; | &quot;blue&quot; | &quot;green&quot;</span></span></code></pre></div>



<p><span class="keyboard-key">&#x1f4d3; 説明</span></p>



<ul class="wp-block-list">
<li><code>as const</code>：配列の中身を変更できないようにし、&#8221;red&#8221; などの固定値として扱う</li>



<li><code>typeof COLORS[number]</code>：配列内の要素を全部取り出して、型にする</li>
</ul>



<p>これで Color型には &#8220;red&#8221;、&#8221;blue&#8221;、&#8221;green&#8221; だけが使えるようになります。</p>



<p><span class="keyboard-key">&#x1f50d; なぜnumberを使うの？</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>type Color = typeof COLORS&#91;number&#93;;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Color </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>この <code>number</code> は「配列の中のすべての値を取り出す」という意味です。配列は <code>COLORS[0]</code>, <code>COLORS[1]</code> のように数字（=number）でアクセスします。</p>



<p>だから <code>COLORS[number]</code> と書くと、「すべてのインデックス番号に対応する値＝全要素」を指すことになります。これは TypeScript の<strong>決まり文句</strong>なので、覚えてしまえばOKです。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc6">オブジェクトで使う as const</span></h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const STATUS = {
  OK: 200,
  NOT_FOUND: 404,
} as const;

type StatusCode = typeof STATUS&#91;keyof typeof STATUS&#93;;
// → 200 | 404</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">STATUS</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">OK</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">200</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">NOT_FOUND</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">404</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> StatusCode </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">STATUS</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">keyof</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">STATUS</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// → 200 | 404</span></span></code></pre></div>



<p><span class="keyboard-key">&#x1f4d3; 説明</span></p>



<ul class="wp-block-list">
<li><code>as const</code>：オブジェクトの中身（200 や 404）を固定する</li>



<li><code>typeof STATUS[keyof typeof STATUS]</code>：すべての値をまとめて型にする</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc7">結局何が便利なの？</span></h2>



<p><code>as const</code> を使うと、値と型の“二重管理”が不要になります。<br>たとえば、ボタンの種類を定義しておきたいとき：</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const BUTTON_TYPES = &#91;"primary", "secondary", "danger"&#93; as const;
type ButtonType = typeof BUTTON_TYPES&#91;number&#93;;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUTTON_TYPES</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">primary</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">secondary</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">danger</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> ButtonType </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUTTON_TYPES</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>このようにしておけば：</p>



<ul class="wp-block-list">
<li>値としてボタンタイプを配列で定義</li>



<li>型としてもそのまま使える（&#8221;primary&#8221; | &#8220;secondary&#8221; | &#8220;danger&#8221;）</li>
</ul>



<p>あとから値を追加・削除しても、型も一緒に変わるので、<strong>管理がラクになってミスも防げる</strong>んです。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/18/shadcn-ui/" title="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-376x212.png 376w" sizes="(max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ</div><div class="blogcard-snippet internal-blogcard-snippet">shadcn/uiは、Tailwind CSSベースで使える高品質なReact UIライブラリです。初心者にもわかりやすく、shadcn/uiの特徴や導入手順、使い方、MUIなど他のライブラリとの違いまで徹底解説。カスタマイズしやすくて実務にも最適な理由を紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">as const のメリット</span></h2>



<p><span class="keyboard-key">&#x274c; as const なし</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const roles = &#91;"admin", "user"&#93;;
type Role = typeof roles&#91;number&#93;; // → string</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">roles</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">user</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Role </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">roles</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// → string</span></span></code></pre></div>



<p><code>"admin"</code> でも 定義していない <code>"manager"</code> でも通ってしまいます。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x2705; as const あり</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const roles = &#91;"admin", "user"&#93; as const;
type Role = typeof roles&#91;number&#93;; // → "admin" | "user"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">roles</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">user</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Role </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">roles</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// → &quot;admin&quot; | &quot;user&quot;</span></span></code></pre></div>



<p>型が限定され、<strong>間違った値を弾ける</strong>ようになります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/20/as-const/">as const って何？「値＝型」にできるTypeScriptの型ガード術</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/20/as-const/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ</title>
		<link>https://it-bokenki.com/2025/07/18/shadcn-ui/</link>
					<comments>https://it-bokenki.com/2025/07/18/shadcn-ui/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Thu, 17 Jul 2025 15:36:58 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Next.js]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4973</guid>

					<description><![CDATA[<p>未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 CSSって実装方法いろいろありますよね。 「とりあえず動くけど、チーム開発だとCSSが競合してグチャグチャになる…」「時間かけ [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/18/shadcn-ui/">【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>CSSって実装方法いろいろありますよね。</p>



<ul class="wp-block-list">
<li><code>.css</code> ファイル作ってインポート</li>



<li>タグに <code>style={{}}</code> で直接書く</li>



<li>Sass や CSS Modules、Styled Components などのライブラリも…</li>
</ul>



<p>「とりあえず動くけど、チーム開発だとCSSが競合してグチャグチャになる…」<br>「時間かけてUI組んだのに、おしゃれにならない…」<br>そんな悩みを抱えていた自分が「これだ！」と思えたのが、<strong>shadcn/ui</strong> というUIライブラリでした。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">shadcn/uiとは？</span></h2>



<p><strong>shadcn/ui</strong> は、Tailwind CSS をベースにした、柔軟で拡張可能な UI コンポーネント集です。</p>



<p>よく使うパーツ（ボタン、モーダル、チェックボックスなど）がすぐ使える状態で提供され、しかも<strong>自分のプロジェクトに直接コンポーネントのコードが追加される</strong>のが特徴です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">他のUIライブラリとの比較</span></h2>



<p><span class="keyboard-key">&#x274c; 普通のUIライブラリ（npmパッケージ）</span></p>



<ul class="wp-block-list">
<li><code>npm install</code> で <strong>ライブラリをインストールするだけ</strong></li>



<li>中身（ボタンの見た目など）は <strong>触れない・カスタムしにくい</strong></li>



<li>例：MUI、Chakra UI、Bootstrap</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x2705; shadcn/ui（プロジェクトに直接追加される）</span></p>



<ul class="wp-block-list">
<li>コマンドで UI コンポーネントの<strong>実物のコードを自分のプロジェクトにコピー</strong>してくれる</li>



<li>コピーされたコンポーネントは <code>/components/ui/button.tsx</code> などに置かれる</li>



<li>自分で<strong>見た目や動きを好きに変更できる</strong>（完全に自作と同じ感覚）</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>&#x25b6; UIライブラリの比較表</p>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-center" data-align="center">ライブラリ</th><th>カスタマイズ性</th><th>スタイリング</th><th>メンテナンス性</th><th class="has-text-align-center" data-align="center">使いやすさ</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center"><strong>shadcn/ui</strong></td><td>◎（自由編集可）</td><td>Tailwind CSS（自由）</td><td>自分で管理（柔軟）</td><td class="has-text-align-center" data-align="center">◯</td></tr><tr><td class="has-text-align-center" data-align="center">MUI</td><td>△（props依存）</td><td>styled-components風</td><td>バージョン依存が強い</td><td class="has-text-align-center" data-align="center">◎</td></tr><tr><td class="has-text-align-center" data-align="center">Chakra UI</td><td>◯（props多い）</td><td>Emotionベース</td><td>安定している</td><td class="has-text-align-center" data-align="center">◎</td></tr><tr><td class="has-text-align-center" data-align="center">Tailwind UI</td><td>△（HTMLベース）</td><td>Tailwind CSS</td><td>商用ライセンス必要</td><td class="has-text-align-center" data-align="center">◯</td></tr><tr><td class="has-text-align-center" data-align="center">Bootstrap</td><td>×（固定）</td><td>独自CSS</td><td>重い＆レガシー</td><td class="has-text-align-center" data-align="center">△</td></tr></tbody></table></figure>



<p><strong>shadcn/uiは「柔軟さ」と「今風の設計」が強み。</strong><br>プロジェクトのデザインや設計方針にこだわりたいチームやエンジニアに向いています。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">shadcn/ui 導入手順</span></h2>



<p>下記の前提条件のもと、shadcn/ui 導入手順をご説明します。</p>



<ul class="wp-block-list">
<li>Next.js（React）プロジェクト</li>



<li>Tailwind CSSがすでに導入済み</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc5">STEP１：初期化</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># 初期セットアップ（初回のみ）
npx shadcn@latest init</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x26a0;&#xfe0f; 注意「shadcn-ui@latest」は非推奨？</span></p>



<figure class="wp-block-image aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="172" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35-1024x172.png" alt="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="wp-image-4974" style="width:691px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35-1024x172.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35-300x50.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35-768x129.png 768w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35.png 1178w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><code>npx shadcn-ui@latest init</code> のコマンドは古いコマンドです。これを使うと「古い CLI です」とエラーが出ることがあります。<strong>現在は上記のように <code>shadcn</code> に名前が変更されています。</strong></p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">STEP２：初期設定 バージョン</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>Need to install the following packages:
shadcn@2.9.2
Ok to proceed? (y) y</code></pre></div>



<ul class="wp-block-list">
<li><code>shadcn</code> のバージョン <code>2.9.2</code> を一時的にインストールして使ってもいいか？</li>



<li><code>npx</code> は必要なパッケージをその場で取得して実行する</li>
</ul>



<p>という確認です。<br><code>y</code> を入力すれば、そのまま <code>shadcn</code> CLI が使えるようになります。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">STEP３：初期設定 UIの色選択</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>Which color do you want to use as base color?
  - Slate
  - Gray
  - Zinc
  - Neutral
  - Stone
  - Red
  - Blue
  - Green</code></pre></div>



<p>UIのカラー選択について聞かれています。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x1f4dd; 補足：色選択の戦略</span></p>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-center" data-align="center">カラー</th><th>特徴・印象</th><th>向いている用途</th><th>傾向・人気度</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center"><strong>Gray</strong></td><td>標準的なグレー。無難で柔軟性が高い</td><td>BtoC向けUI全般。カラフルなアクセントと相性◎</td><td><strong>shadcn初期からの定番</strong></td></tr><tr><td class="has-text-align-center" data-align="center"><strong>Zinc</strong></td><td>クールでメカっぽい無機質な印象</td><td>開発者向けダッシュボード、技術系LPなど</td><td>最近人気上昇中</td></tr><tr><td class="has-text-align-center" data-align="center"><strong>Neutral</strong></td><td>脱色感のある、最も中立的な色合い</td><td>ミニマル・モダンなサイト向け</td><td>人気はやや低め</td></tr><tr><td class="has-text-align-center" data-align="center"><strong>Stone</strong></td><td>わずかに茶系の温かみあり</td><td>雑誌風UI、ナチュラル系、アート系LPなど</td><td>おしゃれ系・差別化目的で選ばれる</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8">STEP４：UIコンポーネントを追加</span></h3>



<p>下記のコマンドを実行すると　src/components/ui配下にそれぞれのUIファイルが作成されます。</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="434" height="246" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33.png" alt="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="wp-image-4975" style="width:300px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33.png 434w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-300x170.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-376x212.png 376w" sizes="auto, (max-width: 434px) 100vw, 434px" /></figure>



<p>Tailwind CSS のクラスを使ってスタイリングされており、即他のコンポーネントでimportして利用できます。フォルダ移動しても問題ありません。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># ボタンを追加
npx shadcn@latest add button

# inputタグを追加
npx shadcn@latest add input

# チェックボックスを追加
npx shadcn@latest add checkbox</code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">shadcn/ui 実装</span></h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import { Input } from "@/components/ui/input";
import { Checkbox } from "@/components/checkbox";
import { Button } from "@/components/ui/button";

export default function Home() {
  return (
      &lt;div className=" flex flex-col items-center space-y-4 mt-10">
        &lt;Input placeholder="メールアドレスを入力" className="w-&#91;18rem&#93;" />

        &lt;div className="flex items-center">
          &lt;Checkbox id="terms" />
          &lt;label htmlFor="terms" className="ml-2 text-sm">
            利用規約に同意する
          &lt;/label>
        &lt;/div>
        
        &lt;Button>送信&lt;/Button>
      &lt;/div>
  );
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Input</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/ui/input</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Checkbox</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/checkbox</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/ui/button</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Home</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C"> flex flex-col items-center space-y-4 mt-10</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Input</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">placeholder</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">メールアドレスを入力</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">w-&#91;18rem&#93;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">flex items-center</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Checkbox</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">id</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">terms</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">htmlFor</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">terms</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ml-2 text-sm</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            利用規約に同意する</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;/label&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">送信</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>&#x25b6; 実際に表示されるUI</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img loading="lazy" decoding="async" width="950" height="392" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.37.45.png" alt="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="wp-image-4977" style="border-width:1px;width:594px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.37.45.png 950w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.37.45-300x124.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.37.45-768x317.png 768w" sizes="auto, (max-width: 950px) 100vw, 950px" /></figure>



<p>たった数行のコードで、ここまでスタイリッシュなフォームが作れます！<br>初期化してから10分かからないくらいです。とても簡単です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">知っておきたい実装方法「スタイルの切り替えスイッチ」</span></h2>



<p>CSSを書いていると、同じ見た目のように見えて少しだけスタイルが違う、というパターンが増えてきます。</p>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">たとえば…</span></p>



<ul class="wp-block-list">
<li>青い「送信」ボタン</li>



<li>赤い「削除」ボタン</li>



<li>枠だけの「戻る」ボタン</li>
</ul>



<p>こんなふうに種類を切り替えたい時に、<strong>毎回 className を条件分岐するのって大変です。</strong>そんなときに便利なのが、<strong><code>variant</code> という考え方</strong>です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc11">variant を使うと、スタイルの管理が楽！</span></h3>



<p><code>variant</code> はざっくり言うと、「スタイルの種類をキーワードで切り替える仕組み」です。</p>



<p>ボタンを例にすると、このように実装できます。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import { Button } from "@/components/ui/button";

export default function Home() {
  return (
      &lt;div className=" flex flex-col items-center space-y-4 mt-10">
        &lt;Button>デフォルト&lt;/Button>
        &lt;Button variant="destructive">削除&lt;/Button>
        &lt;Button variant="outline">戻る&lt;/Button>
      &lt;/div>
  );
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/ui/button</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Home</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C"> flex flex-col items-center space-y-4 mt-10</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">デフォルト</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">variant</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">destructive</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">削除</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">variant</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">outline</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">戻る</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>&#x25b6; 実際に表示されるUI</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img loading="lazy" decoding="async" width="424" height="388" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.46.27.png" alt="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="wp-image-4979" style="border-width:1px;width:293px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.46.27.png 424w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.46.27-300x275.png 300w" sizes="auto, (max-width: 424px) 100vw, 424px" /></figure>



<p>文字列で渡すだけで、見た目がガラッと変わります。<br>この <code>variant="◯◯"</code> がスタイルの切り替えスイッチになるんです。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc12">中身はカスタマイズOK！</span></h3>



<p>実はこの <code>variant</code> の仕組みは <code>button.tsx</code> に定義されています。</p>



<p>たとえば以下のように書かれています。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// components/ui/button.tsx の一部
const buttonVariants = cva(
  "inline-flex items-center justify-center text-sm font-medium",
  {
    variants: {
      variant: {
        default:
          "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
        destructive:
          "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
        outline:
          "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// components/ui/button.tsx の一部</span></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">buttonVariants</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">cva</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">inline-flex items-center justify-center text-sm font-medium</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">variants</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">variant</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">default</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-primary text-primary-foreground shadow-xs hover:bg-primary/90</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">destructive</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">outline</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">defaultVariants</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">variant</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">default</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>つまり、この <code>button.tsx</code> ファイルを<strong>自由に編集</strong>ができます！</p>



<p>たとえば、次のように <code>variant</code> に <code>custom</code> を追加すれば…</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>custom: "bg-purple-500 text-white hover:bg-purple-600"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">custom</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-purple-500 text-white hover:bg-purple-600</span><span style="color: #ECEFF4">&quot;</span></span></code></pre></div>



<p>オリジナルのスタイルが使えるようになります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Button variant="custom">カスタム&lt;/Button></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">variant</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">custom</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">カスタム</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span></code></pre></div>



<p>と書くだけで、紫色のカスタムボタンが表示されます。</p>



<p>ライブラリに依存せず、<strong>自分好みのデザインに柔軟にカスタマイズできる</strong>のが shadcn/ui の大きな魅力です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc13">shadcn/ui のメリット・デメリット</span></h2>



<p><span class="keyboard-key">メリット</span></p>



<ul class="wp-block-list">
<li>&#x2705; <strong>自由に編集できる</strong><br>コードがプロジェクトに含まれるため、業務要件に合わせて修正可能</li>



<li>&#x2705; <strong>Tailwindと相性抜群</strong><br>スタイリングが統一され、CSS設計に悩まなくて済む</li>



<li>&#x2705; <strong>導入が簡単</strong><br><code>npx shadcn@latest add xxx</code> でどんどん追加できる</li>



<li>&#x2705; <strong>全てオープンな React コンポーネント</strong><br>依存性を最小限に抑えられる</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">デメリット</span></p>



<ul class="wp-block-list">
<li>&#x274c; <strong>バージョン管理は自己責任</strong><br>一括更新されないのでメンテの工夫が必要</li>



<li>&#x274c; <strong>生成ファイルが増える</strong><br>チーム内で「どこから来たファイルか」把握する工夫が必要</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>UIライブラリで次におすすめなのはこちらです&#x1f91e;</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/06/14/mui/" title="MUIとは？ReactでおしゃれなUIがすぐ作れるライブラリを解説！" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-5-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-5-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-5-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-5-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">MUIとは？ReactでおしゃれなUIがすぐ作れるライブラリを解説！</div><div class="blogcard-snippet internal-blogcard-snippet">MUIはReactで美しいUIを簡単に作れるライブラリ。豊富なコンポーネントと柔軟なカスタマイズが魅力です。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc14">どんなプロジェクトに向いてる？</span></h2>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-center" data-align="center">向いているプロジェクト</th><th>理由</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center">BtoB SaaS系</td><td>UIに一貫性が必要で、カスタマイズ性が重要</td></tr><tr><td class="has-text-align-center" data-align="center">スタートアップ</td><td>開発速度が早く、軽量で変更に強い構成が求められる</td></tr><tr><td class="has-text-align-center" data-align="center">小〜中規模チーム開発</td><td>全員が同じUIスタイルを使いやすくなる</td></tr><tr><td class="has-text-align-center" data-align="center">Tailwindを使っている</td><td>スタイリングが完全に統一できる</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/18/shadcn-ui/">【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/18/shadcn-ui/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【初心者向け】Next.jsの設定ファイル「next.config.js」の使い方と定番設定3つ</title>
		<link>https://it-bokenki.com/2025/07/10/next-config-js/</link>
					<comments>https://it-bokenki.com/2025/07/10/next-config-js/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Thu, 10 Jul 2025 09:42:41 +0000</pubDate>
				<category><![CDATA[Next.js]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4531</guid>

					<description><![CDATA[<p>※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。 プロが教える、業界最前線のノウハウ【Coloso】 困ってた自分に届けたい話 Next.jsでWebアプリを作っていると [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/10/next-config-js/">【初心者向け】Next.jsの設定ファイル「next.config.js」の使い方と定番設定3つ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><span class="fz-12px">※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。</span></p>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457VJB+C7ZCTU+5Q4A+601S1">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=250630247739&#038;wid=001&#038;eno=01&#038;mid=s00000026713001008000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www15.a8.net/0.gif?a8mat=457VJB+C7ZCTU+5Q4A+601S1" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457VJB+C7ZCTU+5Q4A+5YRHE">プロが教える、業界最前線のノウハウ【Coloso】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>Next.jsでWebアプリを作っていると、見かける <code>next.config.js</code> というファイル。</p>



<p>「設定って何をどうすればいいの？」<br>「これはなんのファイル？」<br>「書かないとダメ？」</p>



<p><strong>触らなくても動くから、触らずそっとファイル閉じた。</strong><br>そんな自分が恥ずかしかったため、今回調査しました。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<h2 class="wp-block-heading"><span id="toc2">next.config.jsとは？</span></h2>



<p><code>next.config.js</code> は、<strong>Next.jsアプリ全体の動作やビルド設定をカスタマイズするためのファイル</strong>です。<br>プロジェクトのルートに配置し、Next.jsの起動時に読み込まれます。</p>



<p><span class="keyboard-key">主な用途の例</span></p>



<ul class="wp-block-list">
<li>外部ドメインの画像を許可する</li>



<li>URLのリダイレクトやリライトを設定する</li>



<li>Reactの開発用チェックを有効にする</li>
</ul>



<p>つまり、<strong>「Next.jsアプリのグローバルな設定」をまとめる場所</strong>です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">初期状態の next.config.js（TypeScriptプロジェクトの場合）</span></h2>



<p>TypeScriptでNext.jsプロジェクトを作った直後は、次のような初期状態になっています。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
};

export default nextConfig;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextConfig</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nextConfig</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> NextConfig </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">/* config options here */</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nextConfig</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>これは「設定内容はここに書いてね」という意味です。<br>設定がなければデフォルトの動作で進みます。必要になったら書き足すスタイルでOKです。</p>



<p><span class="keyboard-key">デフォルト設定の内容</span></p>



<ul class="wp-block-list">
<li><code>NextConfig</code> ：設定の書き間違いを防ぐためのヒントを出してくれる型</li>



<li><code>nextConfig</code> ：いろんな設定項目をこの中に追加できる</li>



<li><code>export default</code>：Next.jsに読み込ませる</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">よく使うNext.jsの設定3選（2025年版）</span></h2>



<p>設定ファイルにいろいろ書けるのは事実ですが、実際に現場でよく使われているのは以下の3つです。</p>



<h3 class="wp-block-heading"><span id="toc5">① 外部画像のURLを許可する（images）</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>images: {
  domains: &#91;"images.unsplash.com"&#93;,
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">images</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  domains</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">images.unsplash.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>Next.jsの <code>&lt;Image /&gt;</code> コンポーネントで<strong>外部サイトの画像（CDNなど）を使いたいときは、その画像のドメインを事前に許可</strong>しておく必要があります。そのため、<strong>ドメイン部分のみ記載</strong>します。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">ここで言う「外部画像」とは？</span></p>



<p>たとえば、Unsplashの画像をそのままURLで表示したい場合<br>※Unsplash：高品質な写真を無料で使えるサイト</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Image
  src="https://images.unsplash.com/photo-12345"
  width={500}
  height={300}
  alt="風景"
/></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Image</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">src</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://images.unsplash.com/photo-12345</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">width</span><span style="color: #81A1C1">={</span><span style="color: #B48EAD">500</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">height</span><span style="color: #81A1C1">={</span><span style="color: #B48EAD">300</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">alt</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">風景</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #81A1C1">/&gt;</span></span></code></pre></div>



<p>このような<strong>外部URLから直接読み込む画像</strong>は、Next.jsのセキュリティルール上、<strong>そのままではブロックされます</strong>。そのため、<strong>読み込みを許可するドメインを明示的に指定する必要がある</strong>のです。</p>



<p><span class="keyboard-key">import する画像とはどう違うの？</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import sampleImage from "@/assets/sample.jpg";

&lt;Image 
　src={sampleImage} 
　width={500} 
　height={300} 
　alt="サンプル" 
/></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">sampleImage</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/assets/sample.jpg</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Image</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">　</span><span style="color: #8FBCBB">src</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">sampleImage</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">　</span><span style="color: #8FBCBB">width</span><span style="color: #81A1C1">={</span><span style="color: #B48EAD">500</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">　</span><span style="color: #8FBCBB">height</span><span style="color: #81A1C1">={</span><span style="color: #B48EAD">300</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">　</span><span style="color: #8FBCBB">alt</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">サンプル</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #81A1C1">/&gt;</span></span></code></pre></div>



<p>このように <code>import</code> した画像は、プロジェクト内にあるファイルなので、<strong>許可設定は不要</strong>です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">② ページのリダイレクト（redirects）</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>async redirects() {
  return &#91;
    {
      source: "/old-page",
      destination: "/new-page",
      permanent: true,
    },
  &#93;;
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">redirects</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> &#91;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">source</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/old-page</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">destination</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/new-page</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">permanent</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">  &#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>古いURLにアクセスされたとき、自動で別ページへ飛ばしたいときに使います。<br><code>permanent: true</code> にすると、<strong>SEO的にも「ページ移動済み」と評価される</strong>のでおすすめです。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">なぜ async なの？</span></p>



<p>この関数が <code>async</code> になっているのは、<strong>必要に応じて外部APIなどから転送先リストを取得するなど、非同期処理ができるようにするため</strong>です。<br>（もちろん、今回のように <code>return</code> だけでもOKです）</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">③ Reactの厳格モードをONにする（reactStrictMode）</span></h3>



<p>開発中に「Reactの間違いを教えてくれるモード」。初心者ほどONがおすすめ！</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>reactStrictMode: true</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">reactStrictMode</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span></span></code></pre></div>



<p>この設定をしたからといって、アプリの動きが変わるわけではありません。</p>



<figure class="wp-block-table"><table><thead><tr><th>設定</th><th>目的</th><th>利便性の違い</th></tr></thead><tbody><tr><td><code>reactStrictMode: false</code></td><td>普通に動く</td><td>バグに気づきにくい</td></tr><tr><td><code>reactStrictMode: true</code></td><td>バグの芽を早めに見つける開発モード</td><td>開発中にミスを教えてくれる</td></tr></tbody></table></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">「true」にすると何が起きるの？</span>　</p>



<p>開発中だけ、以下のようなチェックモードが動くようになります。</p>



<ul class="wp-block-list">
<li><code>useEffect</code> などが <strong>2回実行される</strong>（副作用の確認）</li>



<li>非推奨なReactの使い方を <strong>警告してくれる</strong></li>



<li>コンポーネントの<strong>再レンダリングミス</strong>に気づきやすい</li>
</ul>



<p><span class="keyboard-key">本番には関係ないの？</span></p>



<p><strong>本番（build された後のアプリ）では一切影響なし</strong><br>なので、「true にしておいて損はない」設定です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">よく使う設定を全部まとめるとこうなる</span></h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // 開発モードでReactのチェックを強化
  reactStrictMode: true,

  // 外部ドメインからの画像を許可
  images: {
    domains: &#91;"images.unsplash.com"&#93;,
  },

  // ページのリダイレクト設定
  async redirects() {
    return &#91;
      {
        source: "/old-page",
        destination: "/new-page",
        permanent: true,
      },
      {
        source: "/temporary",
        destination: "/maintenance",
        permanent: false,
      },
    &#93;;
  },
};

export default nextConfig;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextConfig</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nextConfig</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> NextConfig </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// 開発モードでReactのチェックを強化</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">reactStrictMode</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #ECEFF4">,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// 外部ドメインからの画像を許可</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">images</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">domains</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">images.unsplash.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ページのリダイレクト設定</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">redirects</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> &#91;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">source</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/old-page</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">destination</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/new-page</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">permanent</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">source</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/temporary</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">destination</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/maintenance</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">permanent</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    &#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nextConfig</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">補足：環境ごとの切り替えは .NODE_ENV でOK！</span></h2>



<p>昔は <code>next.config.js</code> で環境変数を設定していたこともありましたが、コード内で <code>.NODE_ENV</code> を利用して切り替えるのが一般的です。</p>



<p>これは「今が開発環境かどうか」を判定して、使うAPIのURLを分けている例です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const isDev = process.env.NODE_ENV === "development";

const apiUrl = isDev
  ? "http://localhost:3000/api"
  : "https://example.com/api";
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">isDev</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">NODE_ENV</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">development</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">apiUrl</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">isDev</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">http://localhost:3000/api</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://example.com/api</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p><code>NODE_ENV</code> は実行コマンドで自動で決まります。<br><code>.env</code> や <code>.env.production</code> の<strong>ファイル名で決まるわけではなく</strong>、<strong>コマンドによって自動で切り替わる</strong>と覚えましょう。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>実行コマンド</th><th>NODE_ENVの値</th></tr></thead><tbody><tr><td><code>npm run dev</code></td><td><code>"development"</code>（開発）</td></tr><tr><td><code>npm run build &amp;&amp; start</code></td><td><code>"production"</code>（本番）</td></tr></tbody></table></figure>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x1f4a1; 結論</span> ：環境切り替えについて <strong><code>next.config.js</code> に無理に書く必要はありません。</strong></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">設定を変えたら再起動を忘れずに</span></h2>



<p><code>next.config.ts</code> を変更したら、<strong>開発サーバーを一度止めて再起動</strong>しないと反映されないことがあります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># Ctrl + C で止めてから
npm run dev</code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc11">Next.js をもっと詳しく学びたい人へおすすめの本</span></h2>



<p><span class="keyboard-key">&#x25b6; 動かしながら基礎から学びたい人に</span><br>「まずは手を動かしたい！」という人にぴったりの一冊。基本構造から丁寧に解説されており、Next.jsとReactの連携も自然に身につきます。初学者でもステップを追いやすく、サンプルアプリの構築を通して理解を深められる構成です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41IcDiqx7jL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22">動かして学ぶ！Next.js/React開発入門</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,168<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www10.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; Reactの経験があり、次のステップへ進みたい人に</span><br>「Reactは少し触ったことがあるけど、Next.jsを仕事で使いこなしたい」という人向け。実践を意識した構成で、Webアプリの構造、レンダリング戦略、SEO対応など、現場で必要なノウハウが詰まっています。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41zubkTAnmL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22">React Next.js 実践プログラミング入門: React Next.js モダンWeb開発実践ガイド</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,300<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:17時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; App Routerを本格的に学びたいエンジニアへ</span><br>App Routerを軸に、最新のNext.js開発に対応した本格派。中級者以上の方が「一歩先へ進みたい」と感じたときに読みたい一冊。デザインパターンや設計の視点もあり、長期的に役立つ内容です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/51SeLrEQrQL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22">実践Next.js —— App Routerで進化するWebアプリ開発 エンジニア選書</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,665<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www13.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/10/next-config-js/">【初心者向け】Next.jsの設定ファイル「next.config.js」の使い方と定番設定3つ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/10/next-config-js/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Next.jsでimport地獄を解消！@/でスッキリ書くエイリアス設定術</title>
		<link>https://it-bokenki.com/2025/07/10/nextjs-alias-setting/</link>
					<comments>https://it-bokenki.com/2025/07/10/nextjs-alias-setting/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Thu, 10 Jul 2025 08:19:20 +0000</pubDate>
				<category><![CDATA[IT基礎知識]]></category>
		<category><![CDATA[Next.js]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4261</guid>

					<description><![CDATA[<p>※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。 プロが教える、業界最前線のノウハウ【Coloso】 困ってた自分に届けたい話 開発が進んでくると、ファイルの階層が深くな [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/10/nextjs-alias-setting/">Next.jsでimport地獄を解消！@/でスッキリ書くエイリアス設定術</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><span class="fz-12px">※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。</span></p>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457VJB+C7ZCTU+5Q4A+601S1">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=250630247739&#038;wid=001&#038;eno=01&#038;mid=s00000026713001008000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www15.a8.net/0.gif?a8mat=457VJB+C7ZCTU+5Q4A+601S1" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457VJB+C7ZCTU+5Q4A+5YRHE">プロが教える、業界最前線のノウハウ【Coloso】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>開発が進んでくると、ファイルの階層が深くなっていきますよね。<br>気づけば、<code>../../../components/Button</code> のような import 文が何度も登場…。</p>



<p>「あれ？このファイル、どこから import してたっけ？」<br>「../ を3回戻って、また中に入って……ややこしい！」</p>



<p>そんな風に、<strong>パスが複雑になって迷子になる問題</strong>に悩まされていた方も多いはず。<br>実際、現場でも「エイリアスパスを使わないとPRが通らない」なんてこともあるらしいっす…。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">Next.js をもっと詳しく学びたい人へおすすめの本</span></h2>



<p><span class="keyboard-key">&#x25b6; 動かしながら基礎から学びたい人に</span><br>「まずは手を動かしたい！」という人にぴったりの一冊。基本構造から丁寧に解説されており、Next.jsとReactの連携も自然に身につきます。初学者でもステップを追いやすく、サンプルアプリの構築を通して理解を深められる構成です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41IcDiqx7jL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22">動かして学ぶ！Next.js/React開発入門</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,168<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www10.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; Reactの経験があり、次のステップへ進みたい人に</span><br>「Reactは少し触ったことがあるけど、Next.jsを仕事で使いこなしたい」という人向け。実践を意識した構成で、Webアプリの構造、レンダリング戦略、SEO対応など、現場で必要なノウハウが詰まっています。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41zubkTAnmL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22">React Next.js 実践プログラミング入門: React Next.js モダンWeb開発実践ガイド</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,300<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:17時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; App Routerを本格的に学びたいエンジニアへ</span><br>App Routerを軸に、最新のNext.js開発に対応した本格派。中級者以上の方が「一歩先へ進みたい」と感じたときに読みたい一冊。デザインパターンや設計の視点もあり、長期的に役立つ内容です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/51SeLrEQrQL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22">実践Next.js —— App Routerで進化するWebアプリ開発 エンジニア選書</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,665<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www13.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">エイリアスってなに？</span></h2>



<p>エイリアスとは、長い相対パスを短くわかりやすくするための別名のこと。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Before（地獄）
import Header from "../../../components/shared/Header";

// After（天国）
import Header from "@/components/shared/Header";</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// Before（地獄）</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Header</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">../../../components/shared/Header</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// After（天国）</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Header</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/shared/Header</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>このように、<code>@/</code> を使ってパスを簡略化することで、</p>



<ul class="wp-block-list">
<li>階層の深さに悩まされない</li>



<li>コードが一気に読みやすくなる</li>
</ul>



<p>といったメリットがあります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">Next.js + TypeScriptでの設定方法</span></h2>



<h3 class="wp-block-heading"><span id="toc5">tsconfig.json にパスエイリアスを設定</span></h3>



<p>こうしておくと、<code>@/components</code> は <code>src/components</code> にマッピングされます。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>{
  "compilerOptions": {  // tsのコンパイル設定
    "baseUrl": "./",　　　// パスの基準（プロジェクトルート）
    "paths": {
      "@/*": &#91;"src/*"&#93;　// "@/..." → "src/..." に変換
    }
  }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">compilerOptions</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">: </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// tsのコンパイル設定</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">baseUrl</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">./</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">　　　</span><span style="color: #616E88">// パスの基準（プロジェクトルート）</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">paths</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/*</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">src/*</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;　</span><span style="color: #616E88">// &quot;@/...&quot; → &quot;src/...&quot; に変換</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc6">現場ではどう使われてる？</span></h2>



<p>エイリアスは、以下のように「機能別フォルダ」と組み合わせて使われています。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>エイリアス</th><th>説明</th></tr></thead><tbody><tr><td><code>@/components</code></td><td>見た目のパーツ（ボタンなど）</td></tr><tr><td><code>@/hooks</code></td><td>再利用できる動き（フック）</td></tr><tr><td><code>@/lib</code></td><td>外部サービス連携（APIなど）</td></tr><tr><td><code>@/utils</code></td><td>どこでも使える便利な関数集</td></tr><tr><td><code>@/constants</code></td><td>変わらない設定値のメモ帳</td></tr></tbody></table></figure>



<p>こうすることで、プロジェクトの保守性がグッと上がります。<br><strong>誰が見ても、何を import してるのか一目瞭然</strong>です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc7">豆知識：baseUrl を "./" にしないとどうなる？</span></h2>



<p><code>baseUrl</code> の設定が <code>"./"</code> になっていないと、パスの解決がうまくいきません。<br>たとえば、<code>"src"</code> にしてしまうと <code>@/components</code> が <code>src/src/components</code> になってしまい、バグの原因に。</p>



<p><strong>迷ったら <code>baseUrl</code> は <code>"./"</code> に固定でOK！</strong></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>もっと開発知識つけたい方！こちらの記事はどうですか？</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/03/github-https-ssh-cli/" title="GitHubのHTTPS・SSH・CLIの違いとは？接続方法の選び方をわかりやすく解説！" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/1-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/1-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/1-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/1-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/1-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">GitHubのHTTPS・SSH・CLIの違いとは？接続方法の選び方をわかりやすく解説！</div><div class="blogcard-snippet internal-blogcard-snippet">GitHubへの接続方法にはHTTPS、SSH、CLIの3つがあります。それぞれの特徴や違いを知ることで、よりスムーズなGit操作が可能になります。初心者にもわかりやすく、使い方や選び方を丁寧に解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/10/nextjs-alias-setting/">Next.jsでimport地獄を解消！@/でスッキリ書くエイリアス設定術</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/10/nextjs-alias-setting/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[&#8230;nextauth] とは？Next.jsでログイン認証を実装する方法【App Router対応】</title>
		<link>https://it-bokenki.com/2025/06/27/nextauth/</link>
					<comments>https://it-bokenki.com/2025/06/27/nextauth/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Fri, 27 Jun 2025 03:58:43 +0000</pubDate>
				<category><![CDATA[API]]></category>
		<category><![CDATA[Next.js]]></category>
		<category><![CDATA[バックエンド]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<category><![CDATA[nextauth]]></category>
		<category><![CDATA[ログイン機能]]></category>
		<category><![CDATA[認証機能]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=3536</guid>

					<description><![CDATA[<p>※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。 Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち 困ってた自分に届けたい話 初めてロ [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/06/27/nextauth/">[…nextauth] とは？Next.jsでログイン認証を実装する方法【App Router対応】</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><span class="fz-12px">※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。</span></p>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NZROH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=230528653907&#038;wid=001&#038;eno=01&#038;mid=s00000023513004030000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=3T911P+F006GI+51FE+NZROH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NWRNM">Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち</a></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>初めてログイン機能を作ったとき、「ログイン状態をどうやって保持すればいいの？」「セッションって何？」と疑問だらけ。</p>



<p>ググって出てきたコードをコピペしてみても、うまく動かず。<br>認証の仕組みが見えづらくて、「これで本当に安全なのかな？」と不安になることも…。</p>



<p>そんなときに出会ったのが <code>NextAuth.js</code>。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">Next.js をもっと詳しく学びたい人へおすすめの本</span></h2>



<p><span class="keyboard-key">&#x25b6; 動かしながら基礎から学びたい人に</span><br>「まずは手を動かしたい！」という人にぴったりの一冊。基本構造から丁寧に解説されており、Next.jsとReactの連携も自然に身につきます。初学者でもステップを追いやすく、サンプルアプリの構築を通して理解を深められる構成です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41IcDiqx7jL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22">動かして学ぶ！Next.js/React開発入門</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,168<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www10.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; Reactの経験があり、次のステップへ進みたい人に</span><br>「Reactは少し触ったことがあるけど、Next.jsを仕事で使いこなしたい」という人向け。実践を意識した構成で、Webアプリの構造、レンダリング戦略、SEO対応など、現場で必要なノウハウが詰まっています。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41zubkTAnmL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22">React Next.js 実践プログラミング入門: React Next.js モダンWeb開発実践ガイド</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,300<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:17時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; App Routerを本格的に学びたいエンジニアへ</span><br>App Routerを軸に、最新のNext.js開発に対応した本格派。中級者以上の方が「一歩先へ進みたい」と感じたときに読みたい一冊。デザインパターンや設計の視点もあり、長期的に役立つ内容です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/51SeLrEQrQL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22">実践Next.js —— App Routerで進化するWebアプリ開発 エンジニア選書</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,665<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www13.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">[&#8230;nextauth] ってなに？</span></h2>



<p><code>[...nextauth]</code> は、Next.jsの「<strong>キャッチオールルート</strong>」という仕組みを使った特別なファイルです。</p>



<p>これは、<code>/api/auth/</code> 以下の複数のAPIエンドポイント（ログイン・ログアウトなど）を<br><strong>1つのファイルでまとめて管理できる便利な仕組み</strong>です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">なぜ[&#8230;nextauth] は必要なの？</span></h2>



<p>NextAuth.js を使うと、認証に関するさまざまなAPIが自動的に使われます。</p>



<p>たとえば、こんなエンドポイントがあります。</p>



<figure class="wp-block-table is-style-regular"><table class="has-fixed-layout"><thead><tr><th>APIルート</th><th>概要</th></tr></thead><tbody><tr><td>/api/auth/signin</td><td>ログインページ</td></tr><tr><td>/api/auth/signout</td><td>ログアウト処理</td></tr><tr><td>/api/auth/session</td><td>現在のログイン状態確認</td></tr><tr><td>/api/auth/callback/credentials</td><td>ログイン成功後にユーザー情報を処理</td></tr><tr><td>/api/auth/csrf</td><td>ログイン中のユーザーを識別するための電子的な証明書を取得<br>※電子的な証明書＝トークン</td></tr></tbody></table></figure>



<p>これらを<strong>1つ1つ手動で作ると管理が大変</strong>です。</p>



<p>そこで、<code>[...nextauth]</code> というファイル1つにまとめることで、<br><strong>これらすべてのAPIルートを一括で定義・管理できる</strong>ようになります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc5">App Router で実装</span></h2>



<p>Next.js 13 以降では、新しく登場した <code>app/</code> ディレクトリを使う構成（App Router）が推奨されています。これが <strong>新規プロジェクトやモダンな構成に適した形</strong>です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">App Router のファイル構成</span></h3>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="992" height="378" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.42.png" alt="[...nextauth] とは？Next.jsでログイン実装" class="wp-image-3684" style="width:644px;height:auto" title="[...nextauth] とは？Next.jsでログイン実装" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.42.png 992w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.42-300x114.png 300w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.42-768x293.png 768w" sizes="auto, (max-width: 992px) 100vw, 992px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">App Router の実装内容</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>// app/api/auth/[&#8230;nextauth]/route.ts
// 認証のエントリーポイント
import NextAuth from &#8220;next-auth/next&#8221;;
import { authOptions } from &#8220;@/lib/auth&#8221;;
// NextAuthに設定を渡して処理を作成
const handler = NextAuth(authOptions);
// App RouterではGETとPOSTのメソッドを個別にエクスポートする必要あり
export { handler as GET, handler as POST };
</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// app/api/auth/[...nextauth]/route.ts</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// 認証のエントリーポイント</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextAuth</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/next</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">authOptions</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/lib/auth</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// NextAuthに設定を渡して処理を作成</span></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">NextAuth</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">authOptions</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// App RouterではGETとPOSTのメソッドを個別にエクスポートする必要あり</span></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">GET</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">POST</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>// lib/auth.ts
import CredentialsProvider from &#8220;next-auth/providers/credentials&#8221;;
import type { Session } from &#8220;next-auth&#8221;;
import type { JWT } from &#8220;next-auth/jwt&#8221;;　// NextAuth.jsが使っているトークン（認証情報）の型名
import type { NextAuthOptions } from &#8220;next-auth&#8221;;
// JWTにカスタム情報（role）を追加する場合の型定義
interface Token extends JWT {
  role?: string;
}
export const authOptions: NextAuthOptions = {
  // ① ログイン方法の指定（ここではIDとパスワードによる認証）
  providers: [
    CredentialsProvider({
      name: &#8220;Credentials&#8221;,
      credentials: {
        username: { label: &#8220;ユーザーID&#8221;, type: &#8220;text&#8221; },
        password: { label: &#8220;パスワード&#8221;, type: &#8220;password&#8221; },
      },
      // 認証処理：環境変数のユーザー名・パスワードと一致すれば成功
      async authorize(credentials) {
        if (
          credentials?.username === process.env.ADMIN_USERNAME &amp;&amp;
          credentials?.password === process.env.ADMIN_PASSWORD
        ) {
          return { id: &#8220;1&#8221;, name: &#8220;管理者&#8221;, role: &#8220;admin&#8221; };
        }
        return null; // 認証失敗
      },
    }),
  ],
  // ② カスタムページ（ログイン画面など）を指定
  pages: {
    signIn: &#8220;/auth/signin&#8221;, // 独自ログインページを使う場合
  },
  // ③ セッションの設定（JWT方式を利用）
  session: {
    strategy: &#8220;jwt&#8221;,  // サーバーセッションではなくトークンで管理
    maxAge: 100,      // トークンの有効期限（秒）
  },
  // ④ コールバック処理（トークンやセッションに追加情報を含める）
  callbacks: {
    // JWT作成時：ユーザー情報からroleをtokenに追加
    async jwt({ token, user }: { token: Token; user?: unknown }) {
      if (user &amp;&amp; typeof user === &#8220;object&#8221; &amp;&amp; &#8220;role&#8221; in user) {
        token.role = (user as { role?: string }).role;
      }
      return token;
    },
    // セッション作成時：tokenからroleを取り出してsessionに追加
    async session({ session, token }: { session: Session; token: Token }) {
      session.user = {
        &#8230;session.user,
        role: token.role ?? null,
      } as typeof session.user &amp; { role?: string | null };
      return session;
    },
  },
};
</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// lib/auth.ts</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CredentialsProvider</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/providers/credentials</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Session</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">JWT</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/jwt</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">　</span><span style="color: #616E88">// NextAuth.jsが使っているトークン（認証情報）の型名</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NextAuthOptions</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// JWTにカスタム情報（role）を追加する場合の型定義</span></span>
<span class="line"><span style="color: #81A1C1">interface</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Token</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">extends</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB; font-weight: bold">JWT</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">string</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">authOptions</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextAuthOptions</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ① ログイン方法の指定（ここではIDとパスワードによる認証）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">providers</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> [</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">CredentialsProvider</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Credentials</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">username</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">label</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ユーザーID</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">type</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">password</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">label</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">パスワード</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">type</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">      </span><span style="color: #616E88">// 認証処理：環境変数のユーザー名・パスワードと一致すれば成功</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">authorize</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">?.</span><span style="color: #D8DEE9">username</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">ADMIN_USERNAME</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">?.</span><span style="color: #D8DEE9">password</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">ADMIN_PASSWORD</span></span>
<span class="line"><span style="color: #D8DEE9FF">        ) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">id</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">管理者</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">role</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// 認証失敗</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ]</span><span style="color: #ECEFF4">,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ② カスタムページ（ログイン画面など）を指定</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">pages</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">signIn</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/auth/signin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// 独自ログインページを使う場合</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ③ セッションの設定（JWT方式を利用）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">strategy</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">jwt</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// サーバーセッションではなくトークンで管理</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">maxAge</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">100</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">      </span><span style="color: #616E88">// トークンの有効期限（秒）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ④ コールバック処理（トークンやセッションに追加情報を含める）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">callbacks</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// JWT作成時：ユーザー情報からroleをtokenに追加</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">jwt</span><span style="color: #ECEFF4">({</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> token</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Token</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> user</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">unknown</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">})</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">object</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">role</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">string</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// セッション作成時：tokenからroleを取り出してsessionに追加</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">session</span><span style="color: #ECEFF4">({</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> session</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Session</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> token</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Token</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">})</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">...</span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">role</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">??</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">string</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">null</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">Pages Router で実装</span></h2>



<p><code>pages/</code> ディレクトリを使う旧構成で、Next.js 初期から使われていたルーターです。<br>今でも既存プロジェクトではよく使われていますが、<strong>新規プロジェクトではあまり使われません</strong>。<br>今後は <code>app/</code> を使う App Router が推奨されています。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc9">Pages Router のファイル構成</span></h3>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="1054" height="234" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.58.png" alt="[...nextauth] とは？Next.jsでログイン実装" class="wp-image-3685" style="width:644px;height:auto" title="[...nextauth] とは？Next.jsでログイン実装" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.58.png 1054w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.58-300x67.png 300w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.58-1024x227.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-27-11.36.58-768x171.png 768w" sizes="auto, (max-width: 1054px) 100vw, 1054px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc10">Pages Router の実装内容</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>// pages/api/auth/[&#8230;nextauth].ts
import NextAuth from &#8220;next-auth&#8221;;
import CredentialsProvider from &#8220;next-auth/providers/credentials&#8221;;
import type { Session } from &#8220;next-auth&#8221;;
import type { JWT } from &#8220;next-auth/jwt&#8221;;
// JWTにカスタム情報（role）を追加する場合の型定義
interface Token extends JWT {
  role?: string;
}
export default NextAuth({
  // ① ログイン方法の指定（ここではIDとパスワードによる認証）
  providers: [
    CredentialsProvider({
      name: &#8220;Credentials&#8221;,
      credentials: {
        username: { label: &#8220;ユーザーID&#8221;, type: &#8220;text&#8221; },
        password: { label: &#8220;パスワード&#8221;, type: &#8220;password&#8221; },
      },
      // 認証処理：環境変数のユーザー名・パスワードと一致すれば成功
      async authorize(credentials) {
        if (
          credentials?.username === process.env.ADMIN_USERNAME &amp;&amp;
          credentials?.password === process.env.ADMIN_PASSWORD
        ) {
          return { id: &#8220;1&#8221;, name: &#8220;管理者&#8221;, role: &#8220;admin&#8221; };
        }
        return null; // 認証失敗
      },
    }),
  ],
  // ② カスタムページ（ログイン画面など）を指定
  pages: {
    signIn: &#8220;/auth/signin&#8221;, // 独自ログインページを使う場合
  },
  // ③ セッションの設定（JWT方式を利用）
  session: {
    strategy: &#8220;jwt&#8221;,  // サーバーセッションではなくトークンで管理
    maxAge: 100,      // トークンの有効期限（秒）
  },
  // ④ コールバック処理（トークンやセッションに追加情報を含める）
  callbacks: {
    // JWT作成時：ユーザー情報からroleをtokenに追加
    async jwt({ token, user }: { token: Token; user?: unknown }) {
      if (user &amp;&amp; typeof user === &#8220;object&#8221; &amp;&amp; &#8220;role&#8221; in user) {
        token.role = (user as { role?: string }).role;
      }
      return token;
    },
    // セッション作成時：tokenからroleを取り出してsessionに追加
    async session({ session, token }: { session: Session; token: Token }) {
      session.user = {
        &#8230;session.user,
        role: token.role ?? null,
      } as typeof session.user &amp; { role?: string | null };
      return session;
    },
  },
});</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// pages/api/auth/[...nextauth].ts</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextAuth</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">CredentialsProvider</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/providers/credentials</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Session</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">JWT</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/jwt</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// JWTにカスタム情報（role）を追加する場合の型定義</span></span>
<span class="line"><span style="color: #81A1C1">interface</span><span style="color: #D8DEE9FF"> Token </span><span style="color: #81A1C1">extends</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB; font-weight: bold">JWT</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">string;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">NextAuth</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ① ログイン方法の指定（ここではIDとパスワードによる認証）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">providers</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> [</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">CredentialsProvider</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Credentials</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">credentials</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">username</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">label</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ユーザーID</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">type</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">password</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">label</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">パスワード</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">type</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">      </span><span style="color: #616E88">// 認証処理：環境変数のユーザー名・パスワードと一致すれば成功</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">authorize</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">?.</span><span style="color: #D8DEE9">username</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">ADMIN_USERNAME</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">?.</span><span style="color: #D8DEE9">password</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">ADMIN_PASSWORD</span></span>
<span class="line"><span style="color: #D8DEE9FF">        ) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">id</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">管理者</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">role</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// 認証失敗</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ]</span><span style="color: #ECEFF4">,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ② カスタムページ（ログイン画面など）を指定</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">pages</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">signIn</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/auth/signin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// 独自ログインページを使う場合</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ③ セッションの設定（JWT方式を利用）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">session</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">strategy</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">jwt</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// サーバーセッションではなくトークンで管理</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">maxAge</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">100</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">      </span><span style="color: #616E88">// トークンの有効期限（秒）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ④ コールバック処理（トークンやセッションに追加情報を含める）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">callbacks</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// JWT作成時：ユーザー情報からroleをtokenに追加</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">jwt</span><span style="color: #ECEFF4">({</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> token</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Token</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> user</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">unknown</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">})</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">object</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">role</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">string</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// セッション作成時：tokenからroleを取り出してsessionに追加</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">session</span><span style="color: #ECEFF4">({</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> session</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Session</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> token</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Token </span><span style="color: #ECEFF4">})</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">...</span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">role</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">??</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">string</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">null</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc11">まとめ</span></h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>比較項目</th><th>Pages Router</th><th>App Router</th></tr></thead><tbody><tr><td>構成</td><td>1ファイル完結型</td><td>設定分離型（lib/auth.ts）推奨</td></tr><tr><td>エクスポート方法</td><td>export default</td><td>export { GET, POST }</td></tr><tr><td>推奨</td><td>App Router移行前<br>既存プロジェクト</td><td>Next.js 13以降の新規開発</td></tr></tbody></table></figure>



<p>ファイル1つ（または2つ）で以下すべてのAPIが動く！そのため、それぞれを個別に作る必要なし！</p>



<ul class="wp-block-list">
<li><code>/api/auth/signin</code></li>



<li><code>/api/auth/signout</code></li>



<li><code>/api/auth/session</code></li>



<li><code>/api/auth/callback/credentials</code></li>



<li><code>/api/auth/csrf</code></li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-default">
<a href="https://it-bokenki.com/2025/06/26/azure-blob/" title="Azure Blob Storage にファイルをアップロードする方法【Next.js × React】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-14-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-14-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-14-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-14-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Azure Blob Storage にファイルをアップロードする方法【Next.js × React】</div><div class="blogcard-snippet internal-blogcard-snippet">Next.jsとAzure Blob Storageを使ったファイルアップロードの実装方法を初心者向けに解説。設定手順からReactでのUI作成、APIの書き方まで！</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div><p>The post <a href="https://it-bokenki.com/2025/06/27/nextauth/">[…nextauth] とは？Next.jsでログイン認証を実装する方法【App Router対応】</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/06/27/nextauth/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応</title>
		<link>https://it-bokenki.com/2025/06/26/nextauth-js/</link>
					<comments>https://it-bokenki.com/2025/06/26/nextauth-js/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Thu, 26 Jun 2025 09:12:47 +0000</pubDate>
				<category><![CDATA[API]]></category>
		<category><![CDATA[Next.js]]></category>
		<category><![CDATA[バックエンド]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<category><![CDATA[ログイン機能]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=3615</guid>

					<description><![CDATA[<p>※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。 Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち 困ってた自分に届けたい話 初めてロ [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/06/26/nextauth-js/">Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><span class="fz-12px">※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。</span></p>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NZROH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=230528653907&#038;wid=001&#038;eno=01&#038;mid=s00000023513004030000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=3T911P+F006GI+51FE+NZROH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NWRNM">Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち</a></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>初めてログイン機能を作ったとき、「ログイン状態をどうやって保持すればいいの？」「セッションって何？」と疑問だらけ。</p>



<p>ググって出てきたコードをコピペしてみても、うまく動かず。<br>認証の仕組みが見えづらくて、「これで本当に安全なのかな？」と不安になることも…。</p>



<p>そんなときに出会ったのが <code>NextAuth.js</code>。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">Next.js をもっと詳しく学びたい人へおすすめの本</span></h2>



<p><span class="keyboard-key">&#x25b6; 動かしながら基礎から学びたい人に</span><br>「まずは手を動かしたい！」という人にぴったりの一冊。基本構造から丁寧に解説されており、Next.jsとReactの連携も自然に身につきます。初学者でもステップを追いやすく、サンプルアプリの構築を通して理解を深められる構成です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41IcDiqx7jL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22">動かして学ぶ！Next.js/React開発入門</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,168<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www10.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; Reactの経験があり、次のステップへ進みたい人に</span><br>「Reactは少し触ったことがあるけど、Next.jsを仕事で使いこなしたい」という人向け。実践を意識した構成で、Webアプリの構造、レンダリング戦略、SEO対応など、現場で必要なノウハウが詰まっています。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41zubkTAnmL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22">React Next.js 実践プログラミング入門: React Next.js モダンWeb開発実践ガイド</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,300<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:17時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; App Routerを本格的に学びたいエンジニアへ</span><br>App Routerを軸に、最新のNext.js開発に対応した本格派。中級者以上の方が「一歩先へ進みたい」と感じたときに読みたい一冊。デザインパターンや設計の視点もあり、長期的に役立つ内容です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/51SeLrEQrQL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22">実践Next.js —— App Routerで進化するWebアプリ開発 エンジニア選書</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,665<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www13.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">全体構成</span></h2>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="602" height="750" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-14.50.51.png" alt="Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応" class="wp-image-3618" style="width:425px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-14.50.51.png 602w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-14.50.51-241x300.png 241w" sizes="auto, (max-width: 602px) 100vw, 602px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">認証設定（lib/auth.ts）</span></h2>



<p><strong>Next.js でログイン機能を作るときに必要な「設定ファイル」</strong>です。<br>NextAuth.js というライブラリが、このファイルを見てどう動くか決めます。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc5">NextAuthの設定内容</span></h3>



<h4 class="wp-block-heading"><span><strong>ログイン方式の設定（providers）</strong></span></h4>



<p>「どんな方法でログインできるようにするか」を決める場所です。</p>



<div style="height:1px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">例</span>：</p>



<ul class="wp-block-list">
<li>ユーザー名とパスワードでログイン ： <strong>CredentialsProvider</strong> を使う</li>



<li>Google アカウントでログイン ： <strong>GoogleProvider</strong><code> </code>を使う</li>



<li>GitHub アカウントでログイン ： <strong>GitHubProvider</strong> を使う</li>
</ul>



<p>→ 今回は「IDとパスワードでログインしたい」ので <code>CredentialsProvider</code> を使います。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><span><strong><strong>セッション管理（session）</strong></strong></span></h4>



<p>「ログイン状態（セッション）をどうやって覚えておくか？」を設定します。</p>



<div style="height:1px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">例</span>：</p>



<ul class="wp-block-list">
<li><strong>jwt</strong>：サーバーに保存せず、ログイン情報をクッキーに入れて管理（軽い）</li>



<li><strong>database</strong>：ログイン情報をデータベースに保存（管理がしっかり）</li>
</ul>



<p>→ 今回は簡単な構成にしたいので、<code>jwt</code> を使っています。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><span><strong><strong><strong>コールバック関数（callbacks）</strong></strong></strong></span></h4>



<p>「ログインしたあと、追加で何かしたいとき」に使います。</p>



<div style="height:1px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">例</span>：</p>



<ul class="wp-block-list">
<li>ログインしたユーザーの「名前」や「権限（adminなど）」をセッションに保存する</li>



<li>トークンに extra 情報を加える</li>
</ul>



<p>→ 今回は、「管理者かどうか（role）」をセッションに入れています。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">lib 配下にファイルを配置する理由</span></h3>



<p><code>lib</code> は「<strong>ロジック（処理）や設定などの共通ユーティリティを置く場所</strong>」という意味で使われます。<code>auth.ts</code> は<strong>アプリ全体で使う「認証の設定」</strong> をまとめたものなので、<code>lib</code> に置くのが自然です。</p>



<p><span class="keyboard-key">&#x1f5c2; <strong>配置イメージ</strong></span></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>ディレクトリ</th><th>役割</th></tr></thead><tbody><tr><td><code><strong>lib/</strong></code>配下</td><td>アプリ全体で使い回すロジックや設定の置き場</td></tr><tr><td><strong><code>app/api/</code></strong>配下 　もしくは<strong><code>　　　　　pages/api/</code></strong>配下</td><td>APIルート（APIエンドポイント）</td></tr><tr><td><strong><code>components/</code></strong>配下</td><td>UIの部品化されたパーツの置き場</td></tr></tbody></table></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">実装内容</span></h3>



<p><strong><span class="keyboard-key">&#x26a0;&#xfe0f; 実装時の注意点</span></strong></p>



<ul class="wp-block-list">
<li>ログインID・パスワードは直書き厳禁。今回は.envに直書きしてしまっています。<br>（次回、Azure SQL Databaseにパスワード等を格納する記事出します！）</li>



<li><code>role</code> など独自の情報をセッションやトークンに保持したい場合は、<code>callbacks</code> を使って明示的に追加します。</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>import CredentialsProvider from &#8220;next-auth/providers/credentials&#8221;;
import type { Session } from &#8220;next-auth&#8221;;
import type { JWT } from &#8220;next-auth/jwt&#8221;;
interface Token extends JWT {
  role?: string;
}
export const authOptions = {
  // CredentialsProvider の設定（IDとパスワードでログインさせるための仕組み）
  providers: [
    CredentialsProvider({
      // ログイン画面のフォームの中身
      credentials: {
        username: { label: &#8220;ユーザーID&#8221;, type: &#8220;text&#8221; },
        password: { label: &#8220;パスワード&#8221;, type: &#8220;password&#8221; },
      },
      // 入力されたIDとパスワードが正しいかチェックする関数
      async authorize(credentials) {
        if (
          credentials?.username === process.env.[&#8220;任意の環境変数名&#8221;] &amp;&amp;
          credentials?.password === process.env.[&#8220;任意の環境変数名&#8221;]
        ) {
          return { id: &#8220;1&#8221;, name: &#8220;管理者&#8221;, role: &#8220;admin&#8221; };
        }
        return null;
      },
    }),
  ],
  // 独自に作成するページのパス
  pages: {
    signIn: &#8220;/auth/signin&#8221;,
  },
  // セッションの設定
  session: {
    strategy: &#8220;jwt&#8221; as const,
    maxAge: 100,
  },
  // ログイン後、ユーザー情報（user）やトークン（token）に追加情報（ここでは role）を保持・共有
  callbacks: {
    // useSession() で取り出すとき、session.user にも role を渡す
    async session({ session, token }: { session: Session; token: Token }) {
      session.user = {
        &#8230;session.user,
        role: token.role ?? null,
      } as typeof session.user &amp; { role?: string | null };
      return session;
    },
    // ログイン後、トークンに role を保存
    async jwt({ token, user }: { token: Token; user?: unknown }) {
      if (user &amp;&amp; typeof user === &#8220;object&#8221; &amp;&amp; &#8220;role&#8221; in user) {
        token.role = (user as { role?: string }).role;
      }
      return token;
    },
  },
};
</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">CredentialsProvider</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/providers/credentials</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Session</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">JWT</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/jwt</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">interface</span><span style="color: #D8DEE9FF"> Token </span><span style="color: #81A1C1">extends</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB; font-weight: bold">JWT</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">string;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">authOptions</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// CredentialsProvider の設定（IDとパスワードでログインさせるための仕組み）</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">providers</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> [</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">CredentialsProvider</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">      </span><span style="color: #616E88">// ログイン画面のフォームの中身</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">credentials</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">username</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">label</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ユーザーID</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">type</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">password</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">label</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">パスワード</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">type</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">      </span><span style="color: #616E88">// 入力されたIDとパスワードが正しいかチェックする関数</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">authorize</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">?.</span><span style="color: #D8DEE9">username</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">任意の環境変数名</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">] </span><span style="color: #81A1C1">&amp;&amp;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #D8DEE9">credentials</span><span style="color: #ECEFF4">?.</span><span style="color: #D8DEE9">password</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">任意の環境変数名</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">]</span></span>
<span class="line"><span style="color: #D8DEE9FF">        ) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">id</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">管理者</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">role</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ]</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// 独自に作成するページのパス</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">pages</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">signIn</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/auth/signin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// セッションの設定</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">session</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">strategy</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">jwt</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">maxAge</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">100</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ログイン後、ユーザー情報（user）やトークン（token）に追加情報（ここでは role）を保持・共有</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">callbacks</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// useSession() で取り出すとき、session.user にも role を渡す</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">session</span><span style="color: #ECEFF4">({</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> session</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Session</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> token</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Token </span><span style="color: #ECEFF4">})</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">...</span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">role</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">??</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">string</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">null</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">session</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// ログイン後、トークンに role を保存</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">jwt</span><span style="color: #ECEFF4">({</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> token</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Token</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> user</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">unknown</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">})</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">object</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">role</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> role</span><span style="color: #81A1C1">?:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">string</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">role</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">認証エンドポイント（app/api/auth/[...nextauth]/route.ts）</span></h2>



<p><strong>APIルートの設定</strong>です。NextAuth の設定を使ってログイン処理などを実行できるようにします。</p>



<p><strong><span class="keyboard-key">&#x26a0;&#xfe0f; 実装時の注意点</span></strong></p>



<ul class="wp-block-list">
<li><code>route.ts</code> では NextAuth をラップし、GET/POST 両方のメソッドをエクスポートする必要があります。</li>



<li><code>authOptions</code> を正しく <code>lib/auth.ts</code> からインポートできていることを確認してください。</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>import NextAuth from &#8220;next-auth/next&#8221;;
import { authOptions } from &#8220;@/lib/auth&#8221;;
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextAuth</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/next</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">authOptions</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/lib/auth</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">NextAuth</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">authOptions</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">GET</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">POST</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">アプリ全体で認証を使う（components/Providers.tsx）（app/layout.tsx）</span></h2>



<p><strong><strong>セッション（ログイン状態）をアプリ全体で共有</strong></strong>できるようにするためのコンポーネントです。</p>



<p><strong><strong>アプリのレイアウト全体を </strong><code><strong>Providers</strong></code><strong> で囲み、どのページでもログイン情報を使える</strong></strong>ようにします。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc10">SessionProviderとは</span></h3>



<p><code>SessionProvider</code> は、<strong>ログイン状態（セッション）をアプリ全体で使えるようにするための部品</strong>です。</p>



<p>囲んでいないと、<br><code>useSession()</code>（ログイン状態を取得する関数）<br><code>getSession()</code>（セッション情報を取得する関数）<br>などが正しく動作しません。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc11">SessionProvider を直接 layout.tsxに記載しない理由</span></h3>



<p>Next.js App Router では <strong><code>layout.tsx</code> はサーバーコンポーネントであることが前提</strong> です。なので、以下のような理由で <code>SessionProvider</code> を直接 <code>layout.tsx</code> に書けないことがあります。</p>



<p><span class="keyboard-key">&#x2757;問題の背景</span></p>



<ul class="wp-block-list">
<li><code>SessionProvider</code> は <strong>クライアントコンポーネント（<code>"use client"</code> が必要）</strong></li>



<li>一方で、<code>layout.tsx</code> はデフォルトで <strong>サーバーコンポーネント</strong></li>



<li>サーバーコンポーネントに <code>use client</code> をつけると、<code>metadata</code> などのサーバー専用機能が使えなくなる</li>
</ul>



<p><code>SessionProvider</code> を直接 <code>layout.tsx</code> に書くと、<code>layout.tsx</code> 全体がクライアントコンポーネントになり、Next.js 本来の機能（<code>metadata</code> など）が使えなくなる。</p>



<p>そのため、<strong>別のクライアントコンポーネントに切り出してラップする</strong>のが推奨されているわけです。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc12">実装内容</span></h3>



<p><span class="keyboard-key">&#x2705; 解決策</span>：<code>&lt;Providers&gt;</code> コンポーネントを別に作成して、ラップする！！</p>



<p><code>Providers.tsx</code> を作って <code>"use client"</code> をつけることで、</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>&#8220;use client&#8221;;
import { SessionProvider } from &#8220;next-auth/react&#8221;;
export function Providers({ children }: { children: React.ReactNode }) {
  return &lt;SessionProvider>{children}&lt;/SessionProvider>;
}</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">use client</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SessionProvider</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/react</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Providers</span><span style="color: #ECEFF4">({</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">children</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> children</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> React</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">ReactNode </span><span style="color: #ECEFF4">})</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">SessionProvider</span><span style="color: #81A1C1">&gt;{</span><span style="color: #D8DEE9">children</span><span style="color: #81A1C1">}&lt;/</span><span style="color: #8FBCBB">SessionProvider</span><span style="color: #81A1C1">&gt;;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>これを <code>layout.tsx</code> 側で下記のようにラップする。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>import type { Metadata } from &#8220;next&#8221;;
import { Providers } from &#8220;@/components/Providers&#8221;;
import &#8220;./globals.css&#8221;;
export const metadata: Metadata = {
  title: &#8220;Create Next App&#8221;,
  description: &#8220;Generated by create next app&#8221;,
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    &lt;html lang=&#8221;en&#8221;>
      &lt;body>
        &lt;Providers>{children}&lt;/Providers>
      &lt;/body>
    &lt;/html>
  );
}</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Metadata</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Providers</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/Providers</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">./globals.css</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">metadata</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Metadata </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">title</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Create Next App</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">description</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Generated by create next app</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">RootLayout</span><span style="color: #ECEFF4">({</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">children</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> children</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> React</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">ReactNode </span><span style="color: #ECEFF4">})</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;html</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">lang</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">en</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;body&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Providers</span><span style="color: #81A1C1">&gt;{</span><span style="color: #D8DEE9">children</span><span style="color: #81A1C1">}&lt;/</span><span style="color: #8FBCBB">Providers</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/body&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;/html&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc13">ログインフォーム（app/auth/signin/page.tsx）</span></h2>



<p><strong><strong>ユーザーがログインIDとパスワードを入力</strong></strong>し、ログイン処理を実行するフォームです。</p>



<p><strong><span class="keyboard-key">&#x26a0;&#xfe0f; 実装時の注意点</span></strong></p>



<ul class="wp-block-list">
<li><code>signIn("credentials")</code> の引数 <code>redirect: false</code> を忘れると、自動遷移してしまいエラー処理が難しくなります。</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>&#8220;use client&#8221;;
import { useState } from &#8220;react&#8221;;
import { signIn } from &#8220;next-auth/react&#8221;;
export default function SignInForm() {
  const [userId, setUserId] = useState(&#8220;&#8221;);
  const [password, setPassword] = useState(&#8220;&#8221;);
  const [errorMsg, setErrorMsg] = useState(&#8220;&#8221;);
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setErrorMsg(&#8220;&#8221;);
    const res = await signIn(&#8220;credentials&#8221;, {
      redirect: false,
      username: userId,
      password,
    });
    if (res?.error) {
      setErrorMsg(&#8220;ログインIDまたはパスワードが間違っています&#8221;);
    } else if (res?.ok) {
      window.location.href = &#8220;/download&#8221;;
    } else {
      setErrorMsg(&#8220;不明なエラーが発生しました&#8221;);
    }
  };
  return (
    &lt;div className=&#8221;flex items-center justify-center min-h-screen bg-cover bg-center&#8221; style={{ backgroundImage: &#8220;url(&#8216;/images/white-background.png&#8217;)&#8221; }}>
      &lt;form onSubmit={handleSubmit} className=&#8221;bg-white p-8 rounded shadow-md w-[500px] mx-auto&#8221;>
        &lt;h1 className=&#8221;text-2xl font-bold mb-6 text-center&#8221;>ログイン&lt;/h1>
        &lt;label className=&#8221;block mb-4&#8243;>
          &lt;span className=&#8221;block text-gray-700 font-semibold mb-1&#8243;>ログインID&lt;/span>
          &lt;input type=&#8221;text&#8221; value={userId} onChange={(e) => setUserId(e.target.value)} required className=&#8221;w-full px-3 py-2 border border-gray-300 rounded&#8221; />
        &lt;/label>
        &lt;label className=&#8221;block mb-4&#8243;>
          &lt;span className=&#8221;block text-gray-700 font-semibold mb-1&#8243;>パスワード&lt;/span>
          &lt;input type=&#8221;password&#8221; value={password} onChange={(e) => setPassword(e.target.value)} required className=&#8221;w-full px-3 py-2 border border-gray-300 rounded&#8221; />
        &lt;/label>
        {errorMsg &amp;&amp; &lt;p className=&#8221;text-red-600 text-center mb-4&#8243;>{errorMsg}&lt;/p>}
        &lt;button type=&#8221;submit&#8221; className=&#8221;w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700&#8243;>ログイン&lt;/button>
      &lt;/form>
    &lt;/div>
  );
}</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">use client</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">useState</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">react</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">signIn</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/react</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">SignInForm</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9">userId</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setUserId</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9">password</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setPassword</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9">errorMsg</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setErrorMsg</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">handleSubmit</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">e</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> React</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">FormEvent</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">preventDefault</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">setErrorMsg</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">signIn</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">credentials</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">redirect</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">username</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">userId</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">password</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">?.</span><span style="color: #D8DEE9">error</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">setErrorMsg</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ログインIDまたはパスワードが間違っています</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">?.</span><span style="color: #D8DEE9">ok</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">window</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">location</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">href</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/download</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">setErrorMsg</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">不明なエラーが発生しました</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">flex items-center justify-center min-h-screen bg-cover bg-center</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">style</span><span style="color: #81A1C1">={</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">backgroundImage</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">url(&#39;/images/white-background.png&#39;)</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">}&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;form</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">onSubmit</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">handleSubmit</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-white p-8 rounded shadow-md w-[500px] mx-auto</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;h1</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text-2xl font-bold mb-6 text-center</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">ログイン</span><span style="color: #81A1C1">&lt;/h1&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">block mb-4</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;span</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">block text-gray-700 font-semibold mb-1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">ログインID</span><span style="color: #81A1C1">&lt;/span&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;input</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">value</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">userId</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">onChange</span><span style="color: #81A1C1">={</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">setUserId</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">target</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">value</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">required</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">w-full px-3 py-2 border border-gray-300 rounded</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;/label&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">block mb-4</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;span</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">block text-gray-700 font-semibold mb-1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">パスワード</span><span style="color: #81A1C1">&lt;/span&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;input</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">value</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">password</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">onChange</span><span style="color: #81A1C1">={</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">setPassword</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">target</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">value</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">required</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">w-full px-3 py-2 border border-gray-300 rounded</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;/label&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">{</span><span style="color: #D8DEE9">errorMsg</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;p</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text-red-600 text-center mb-4</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;{</span><span style="color: #D8DEE9">errorMsg</span><span style="color: #81A1C1">}&lt;/p&gt;}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">submit</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">ログイン</span><span style="color: #81A1C1">&lt;/button&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/form&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc14">未ログイン時のログイン誘導（components/Login.tsx）</span></h2>



<p><strong><strong>ユーザーが未ログインだった場合に、ログインボタンを表示してログイン画面に誘導</strong></strong>する処理です。</p>



<p><strong><span class="keyboard-key">&#x26a0;&#xfe0f; 実装時の注意点</span></strong></p>



<ul class="wp-block-list">
<li><code>useSession()</code> を使うには、呼び出し元が <code>SessionProvider</code> 配下である必要があります。</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>&#8220;use client&#8221;;
import { signIn } from &#8220;next-auth/react&#8221;;
export default function Login() {
  return (
    &lt;div className=&#8221;mt-8 text-center&#8221;>
      &lt;button
        className=&#8221;text-blue-600 underline&#8221;
        onClick={() => signIn(undefined, { callbackUrl: &#8220;/auth/signin&#8221; })}
      >
        &#x1f512; 管理者ログインはこちら
      &lt;/button>
    &lt;/div>
  );
}
</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">use client</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">signIn</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next-auth/react</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Login</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">mt-8 text-center</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;button</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text-blue-600 underline</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">onClick</span><span style="color: #81A1C1">={</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">signIn</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">undefined</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">callbackUrl</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/auth/signin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        &#x1f512; 管理者ログインはこちら</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/button&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc15">実行画面</span></h2>



<p>下記のリンク押下で、ログイン画面が表示される</p>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="86" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.06-1024x86.png" alt="Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応" class="wp-image-3668" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.06-1024x86.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.06-300x25.png 300w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.06-768x64.png 768w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.06.png 1360w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>ログインID・パスワードを入力</p>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="595" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.20-1024x595.png" alt="Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応" class="wp-image-3669" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.20-1024x595.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.20-300x174.png 300w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.20-768x447.png 768w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.20.png 1424w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>ログイン完了したら、管理者画面が表示される（この画面のコードはなし）</p>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="282" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.39-1024x282.png" alt="Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応" class="wp-image-3670" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.39-1024x282.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.39-300x83.png 300w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.39-768x212.png 768w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.39-1536x424.png 1536w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-26-18.09.39.png 1646w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-default">
<a href="https://it-bokenki.com/2025/06/16/use-client/" title="Next.jsの「use client」とは？サーバーコンポーネントとクライアントコンポーネントの違い" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-12-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-12-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-12-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-12-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Next.jsの「use client」とは？サーバーコンポーネントとクライアントコンポーネントの違い</div><div class="blogcard-snippet internal-blogcard-snippet">Next.jsの &quot;use client&quot; の意味と、サーバー・クライアントコンポーネントの違いを初心者向けに解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div><p>The post <a href="https://it-bokenki.com/2025/06/26/nextauth-js/">Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/06/26/nextauth-js/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Next.jsの「use client」とは？サーバーコンポーネントとクライアントコンポーネントの違い</title>
		<link>https://it-bokenki.com/2025/06/16/use-client/</link>
					<comments>https://it-bokenki.com/2025/06/16/use-client/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Mon, 16 Jun 2025 07:42:42 +0000</pubDate>
				<category><![CDATA[Next.js]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=3495</guid>

					<description><![CDATA[<p>※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。 Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち 困ってた自分に届けたい話 Next [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/06/16/use-client/">Next.jsの「use client」とは？サーバーコンポーネントとクライアントコンポーネントの違い</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><span class="fz-12px">※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。</span></p>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NZROH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=230528653907&#038;wid=001&#038;eno=01&#038;mid=s00000023513004030000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=3T911P+F006GI+51FE+NZROH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NWRNM">Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち</a></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-text-align-center"></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>Next.jsでフロントの機能を実装していたとき、<br>「なんでこのコード、動かないんだろう…？」と何度もつまずいていました。</p>



<p>とくに <code>useState</code> や <code>useEffect</code> を使おうとすると、<br>エラーが出たり、真っ白な画面になったりして、「？？？」の連続。</p>



<p>いろいろ調べてやっと気づいたのが、<strong><code>"use client"</code> を書いてなかった</strong>。<br>そんな一言だけで動くのか…と、拍子抜けしたような記憶がまだあります。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">Next.js をもっと詳しく学びたい人へおすすめの本</span></h2>



<p><span class="keyboard-key">&#x25b6; 動かしながら基礎から学びたい人に</span><br>「まずは手を動かしたい！」という人にぴったりの一冊。基本構造から丁寧に解説されており、Next.jsとReactの連携も自然に身につきます。初学者でもステップを追いやすく、サンプルアプリの構築を通して理解を深められる構成です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41IcDiqx7jL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22">動かして学ぶ！Next.js/React開発入門</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,168<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www10.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; Reactの経験があり、次のステップへ進みたい人に</span><br>「Reactは少し触ったことがあるけど、Next.jsを仕事で使いこなしたい」という人向け。実践を意識した構成で、Webアプリの構造、レンダリング戦略、SEO対応など、現場で必要なノウハウが詰まっています。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41zubkTAnmL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22">React Next.js 実践プログラミング入門: React Next.js モダンWeb開発実践ガイド</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,300<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:17時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; App Routerを本格的に学びたいエンジニアへ</span><br>App Routerを軸に、最新のNext.js開発に対応した本格派。中級者以上の方が「一歩先へ進みたい」と感じたときに読みたい一冊。デザインパターンや設計の視点もあり、長期的に役立つ内容です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/51SeLrEQrQL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22">実践Next.js —— App Routerで進化するWebアプリ開発 エンジニア選書</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,665<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www13.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">なぜ "use client" が必要なの？</span></h2>



<p>Next.js 13 以降（App Router 環境）では、<strong>コンポーネントは基本的にサーバーコンポーネント</strong>として扱われます。<br>そのため、以下のような<strong>ブラウザでしか動かない処理</strong>は、デフォルトでは使えません。</p>



<ul class="wp-block-list">
<li><code>useState</code>, <code>useEffect</code>, <code>useRef</code> などの React のクライアントフック</li>



<li><code>window</code> や <code>document</code> などのブラウザAPI</li>



<li>ボタンクリックなどのイベント処理</li>
</ul>



<p>これらを使いたいときには、<strong>そのファイルの先頭に <code>"use client"</code> と書く必要がある</strong>というのが、Next.js App Router のルールです。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">サーバーコンポーネントとは？</span></h2>



<p>Next.js では、特に何も書かないコンポーネントは「サーバーコンポーネント」として扱われます。</p>



<ul class="wp-block-list">
<li>サーバー上で実行される（ユーザーのブラウザでは動かない）</li>



<li>セキュアにデータを扱える</li>



<li>F12（開発者ツール）でコードを見ることができない</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>export default function MyComponent() {
  // サーバー側で実行される
  return &lt;div>サーバーから描画されました&lt;/div>;
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MyComponent</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// サーバー側で実行される</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> &lt;</span><span style="color: #8FBCBB">div</span><span style="color: #D8DEE9FF">&gt;</span><span style="color: #D8DEE9">サーバーから描画されました</span><span style="color: #81A1C1">&lt;/</span><span style="color: #D8DEE9">div</span><span style="color: #81A1C1">&gt;;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc5">クライアントコンポーネントとは？</span></h2>



<p><code>"use client"</code> をファイルの先頭に書くと、そのコンポーネントは「クライアントコンポーネント」として動きます。</p>



<ul class="wp-block-list">
<li>ブラウザ側で実行される</li>



<li>ボタンクリックやフォーム送信などの動作ができる</li>



<li>開発者ツールで中身が見える（HTMLやJS）</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>"use client";

export default function ClientComponent() {
  const handleClick = () => alert("クリックされました");

  return &lt;button onClick={handleClick}>クリック&lt;/button>;
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">use client</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ClientComponent</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">handleClick</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">alert</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">クリックされました</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> &lt;</span><span style="color: #8FBCBB">button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">onClick</span><span style="color: #D8DEE9FF">=</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF">handleClick</span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">&gt;</span><span style="color: #D8DEE9">クリック</span><span style="color: #81A1C1">&lt;/</span><span style="color: #D8DEE9">button</span><span style="color: #81A1C1">&gt;;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc6">一度クライアントにすると、どうなるの？</span></h2>



<h3 class="wp-block-heading"><span id="toc7">親が "use client" を持っていると？</span></h3>



<p>あるコンポーネントの先頭に <code>"use client"</code> と書くと、その<strong>ファイル全体がクライアントコンポーネント</strong>として扱われます。<br>中に書かれたロジックも、サーバーではなくブラウザ上で動く前提になります。</p>



<p>たとえばその中に <code>fetch()</code> や <code>useState()</code> があれば、それはクライアント上で動きますし、<strong>重い処理やセキュアな処理もブラウザに送られるリスクがあります。</strong></p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8"> 途中でサーバーに戻せるのか？</span></h3>



<p>Next.js では、ファイルの先頭に <code>"use client"</code> を書くことで、その<strong>ファイル全体がクライアントコンポーネント</strong>として扱われます。<br>途中で <code>"use server"</code> に切り替えるような書き方はできません。</p>



<p>ただし、<strong><code>"use client"</code> を削除すれば、そのファイルは再びサーバーコンポーネントに戻ります</strong>。<br>つまり「一度クライアントにしたら元に戻せない」というわけではなく、<strong>明示的に切り替え直せばOK</strong>という仕組みです。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">よりセキュアにしたいときは？</span></h2>



<p>フォーム送信などで <code>await fetch("/api/contact", {...})</code> のような処理をすることがあります。 この処理を「クライアントコンポーネント内で実行」すると、リクエスト内容がF12で見えてしまうことがあります。</p>



<p>よりセキュアにしたい場合は、下記の構成にしましょう！</p>



<ul class="wp-block-list">
<li>ユーザー入力（例：名前やメール）をクライアント側で受け取る</li>



<li>それを <code>API Route</code>（サーバー側）に送って処理する </li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">まとめ</span></h2>



<figure class="wp-block-table is-style-regular"><table><thead><tr><th><strong>項目</strong></th><th><strong>サーバーコンポーネント</strong></th><th><strong>クライアントコンポーネント</strong></th></tr></thead><tbody><tr><td><code>"use client"</code> 必要か</td><td>&#x274c; 不要</td><td>&#x2705; 必要</td></tr><tr><td>実行される場所</td><td>サーバー上</td><td>ブラウザ上</td></tr><tr><td>F12で見えるか</td><td>&#x274c; 見えない</td><td>&#x2705; 見える</td></tr><tr><td>できること</td><td>データ取得や表示のみ</td><td>ボタン操作・イベント・状態管理などが可能</td></tr></tbody></table></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/06/11/zod/" title="Zodとは？React Hook Formとの連携でバリデーション実装" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-1-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-1-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-1-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-1-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Zodとは？React Hook Formとの連携でバリデーション実装</div><div class="blogcard-snippet internal-blogcard-snippet">TypeScriptで使えるバリデーションライブラリ「Zod」の基本と、React Hook Formとの連携方法を解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div><p>The post <a href="https://it-bokenki.com/2025/06/16/use-client/">Next.jsの「use client」とは？サーバーコンポーネントとクライアントコンポーネントの違い</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/06/16/use-client/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>axiosとは？初心者でもわかる使い方・fetchとの違いを解説</title>
		<link>https://it-bokenki.com/2025/06/16/axios/</link>
					<comments>https://it-bokenki.com/2025/06/16/axios/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Mon, 16 Jun 2025 07:10:02 +0000</pubDate>
				<category><![CDATA[API]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<category><![CDATA[axios]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=3463</guid>

					<description><![CDATA[<p>Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち axiosとは？ axios は、JavaScriptでAPI通信（サーバーとのやり取り）を簡単に行うための外部ライブラリです。 シン [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/06/16/axios/">axiosとは？初心者でもわかる使い方・fetchとの違いを解説</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>どもども<br>今回は「axios（アクシオス）」について解説します。</p>
</div></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/5-1-150x150.png" alt="バグヲ" class="speech-icon-image"/></figure><div class="speech-name">バグヲ</div></div><div class="speech-balloon">
<p>API通信っていろいろあって混乱するんだけど、<br>axiosってなにが便利なの？</p>
</div></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>こんなあなたにピッタリな記事&#x1f447;</p>



<div style="height:15px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li>axiosってなに？</li>



<li>axiosとfetchの違いは？</li>



<li>API通信がよくわからない</li>
</ul>



<p>がまぁまぁわかります！</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NZROH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=230528653907&#038;wid=001&#038;eno=01&#038;mid=s00000023513004030000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=3T911P+F006GI+51FE+NZROH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NWRNM">Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち</a></p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-default">
<a href="https://it-bokenki.com/2025/06/16/async-await-promise-basic/" title="async/awaitとPromiseの違いとは？" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-10-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-10-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-10-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-10-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">async/awaitとPromiseの違いとは？</div><div class="blogcard-snippet internal-blogcard-snippet">非同期処理が難しいと感じている方へ。async/await・Promise・try/catch の基本をやさしく解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc1">axiosとは？</span></h2>



<p><strong><code>axios</code></strong> は、JavaScriptでAPI通信（サーバーとのやり取り）を簡単に行うための<strong>外部ライブラリ</strong>です。</p>



<p><strong>シンプルなコードで通信が実現できます。</strong></p>



<p><span class="keyboard-key">例</span>：</p>



<ul class="wp-block-list">
<li>Webページを開いたときにユーザー情報を取得したい</li>



<li>入力フォームからデータをサーバーに送りたい</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">axiosは何ができるの？</span></h2>



<p><code>axios</code>を使うと、以下のような操作が簡単にできます。</p>



<ul class="wp-block-list">
<li>GETリクエスト（データを取得）</li>



<li>POSTリクエスト（データを送信）</li>



<li>JSONデータの自動変換</li>



<li>エラー処理（HTTPステータスも catch できる）</li>



<li>タイムアウトやリトライの設定</li>



<li>リクエストヘッダーの共通管理</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">axiosとfetchの違いは？</span></h2>



<p>初心者にとって混乱しやすいのがここ。実は、JavaScriptには標準の通信手段として <code>fetch</code> という関数もあります。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc4">同じGET処理をaxiosとfetchで書くと？</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// fetch版
fetch("https://api.example.com/users")
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));

// axios版
import axios from "axios";

axios.get("https://api.example.com/users")
  .then(res => console.log(res.data))
  .catch(err => console.error(err));</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// fetch版</span></span>
<span class="line"><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://api.example.com/users</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">())</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">catch</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// axios版</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">axios</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">axios</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">axios</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://api.example.com/users</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">catch</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<figure class="wp-block-table is-style-stripes"><table class="has-fixed-layout"><thead><tr><th>比較項目</th><th>fetch</th><th>axios</th></tr></thead><tbody><tr><td>JSON変換</td><td><code>.json()</code> が毎回必要</td><td>自動で変換、<code>res.data</code> ですぐ使える</td></tr><tr><td>エラー処理</td><td>通信エラーしか catch できない</td><td>HTTPエラー（400, 500番台）も catch 可能</td></tr><tr><td>タイムアウト設定</td><td>自力でAbortControllerが必要</td><td><code>timeout</code> オプションですぐ設定可能</td></tr><tr><td>リクエスト共通化</td><td>毎回ヘッダー設定などを記述</td><td><code>axios.defaults</code> で一括設定可能</td></tr><tr><td>2025年の使用状況</td><td>学習・小規模開発に多い</td><td>チーム・実務では今もaxiosが主流</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc5">axiosとfetch どっちを使えばいいの？</span></h3>



<p>&#x2705;&#xfe0f; <strong>学習や練習なら fetch でもOK</strong><br>ライブラリ不要で軽い</p>



<p>&#x2705;&#xfe0f; <strong>実務やチーム開発なら axios をおすすめ</strong><br>冗長な処理を減らせて、保守しやすく、失敗しづらい</p>



<p>2025年現在でも、<strong>ReactやVueなどの現場ではaxiosがよく使われています。</strong></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc6">axiosの使い方</span></h2>



<h3 class="wp-block-heading"><span id="toc7">axiosインストール方法</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>npm install axios
# または
yarn add axios</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8">基本的な使い方（GET/POST）</span></h3>



<p>axiosを使って、サーバーからデータを取得（GET）・送信（POST）する例です。<br><code>res.data</code> でサーバーからのデータにアクセスできます。<br>エラーが起きたときは <code>.catch()</code> で内容を確認できます。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>// GETリクエスト
axios.get(&#8220;/api/user&#8221;)
  .then(res => console.log(res.data))
  .catch(err => console.error(err));
// POSTリクエスト
axios.post(&#8220;/api/user&#8221;, { name: &#8220;太郎&#8221; })
  .then(res => console.log(res.data))
  .catch(err => console.error(err));
</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// GETリクエスト</span></span>
<span class="line"><span style="color: #D8DEE9">axios</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/api/user</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">catch</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// POSTリクエスト</span></span>
<span class="line"><span style="color: #D8DEE9">axios</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">post</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/api/user</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">太郎</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">catch</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">まとめ</span></h2>



<ul class="wp-block-list">
<li>axiosは、JavaScriptでAPI通信を行うための便利なライブラリ</li>



<li>fetchよりも書きやすく、実務で使いやすい工夫がたくさん</li>



<li>初心者はまず「GETでデータ取得 → .then(res.data)」を覚えればOK！</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/06/16/axios/">axiosとは？初心者でもわかる使い方・fetchとの違いを解説</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/06/16/axios/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>async/awaitとPromiseの違いとは？</title>
		<link>https://it-bokenki.com/2025/06/16/async-await-promise-basic/</link>
					<comments>https://it-bokenki.com/2025/06/16/async-await-promise-basic/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Mon, 16 Jun 2025 06:29:26 +0000</pubDate>
				<category><![CDATA[IT基礎知識]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<category><![CDATA[async/await]]></category>
		<category><![CDATA[Promise]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=3430</guid>

					<description><![CDATA[<p>でじぼうです。 この記事では、JavaScriptの中でもつまずきやすい「非同期処理」について、丁寧に解説します。 Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち 非同期処理ってなに [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/06/16/async-await-promise-basic/">async/awaitとPromiseの違いとは？</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>でじぼうです。</p>



<p>この記事では、JavaScriptの中でもつまずきやすい「非同期処理」について、丁寧に解説します。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="でじぼう" class="speech-icon-image"/></figure><div class="speech-name">でじぼう</div></div><div class="speech-balloon">
<p>この記事は下記の方がおすすめ！</p>



<ul class="wp-block-list">
<li style="font-size:15px">非同期処理ってなに？</li>



<li style="font-size:15px">async/awaitってなに？</li>



<li style="font-size:15px">async/awaitとPromiseの違いとは？</li>
</ul>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NZROH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=230528653907&#038;wid=001&#038;eno=01&#038;mid=s00000023513004030000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=3T911P+F006GI+51FE+NZROH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NWRNM">Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち</a></p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-embed is-type-wp-embed is-provider-it wp-block-embed-it"><div class="wp-block-embed__wrapper">
<a href="https://it-bokenki.com/2025/06/16/zod-object-validation/" title="Zodの .object() とセットで使うバリデーション構文まとめ" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-9-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-9-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-9-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-9-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Zodの .object() とセットで使うバリデーション構文まとめ</div><div class="blogcard-snippet internal-blogcard-snippet">Zodの.object()と組み合わせて使うpartialやsuperRefineなどの構文を、初心者にもわかりやすく解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc1">非同期処理ってなに？</span></h2>



<p>「非同期処理」とは、<span class="marker"><strong>時間のかかる処理を待っている間に、他の作業を進められるようにする仕組み</strong></span>です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc2"> 例：サーバーからデータを取得する場合</span></h3>



<p>通常のウェブサイトでは、次のようなことがよくあります</p>



<ol start="1" class="wp-block-list">
<li>サイトを開くときに、サーバーからデータを取りに行く</li>



<li>この取得に数秒かかることもある</li>



<li>もしデータを待っている間に画面が止まっていたら、ユーザー体験が悪くなる</li>
</ol>



<p>そこで使われるのが「<strong><span class="marker">非同期処理</span></strong>」です。</p>



<p>非同期処理にすると、データを待っている間にも他の操作を続けることができます。ユーザーにとってスムーズな体験を実現できるのです。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">Promise（プロミス）とは？</span></h2>



<p>あとで<span class="marker"><strong>「結果が返ってくるよ！」と約束してくれる仕組み</strong></span>です。</p>



<p>JavaScriptでは、時間がかかる処理（たとえば fetch や setTimeout）に対して、 「すぐには結果が出ないけど、終わったら結果を返すね！」という <span class="marker"><strong>箱</strong></span> を渡してくれます。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc4">Promiseの状態は3つ</span></h3>



<p>Promise は、非同期処理の進行に応じて、下記のいずれかの状態を取ります。</p>



<figure class="wp-block-table is-style-stripes"><table class="has-fixed-layout"><thead><tr><th>項目</th><th>状態</th></tr></thead><tbody><tr><td><code><code><span class="marker"><strong>pending</strong></span></code>（ペンディング）</code></td><td>&#x23f3; 実行中</td></tr><tr><td><code><code><strong><span class="marker">fulfilled</span></strong></code>（フルフィルド）</code></td><td>&#x2705; 完了</td></tr><tr><td><code><span class="marker"><strong>rejected</strong></span></code>（リジェクテッド）</td><td>&#x274c; エラー</td></tr></tbody></table></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc5">.then() / .catch() の使い方</span></h3>



<p><code>Promise</code> が返される処理には、結果が返ってきたあとにどう処理するかを <code>.then()</code> と <code>.catch()</code> で書くことができます。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>fetch(&#8220;https://example.com&#8221;)
  .then((res) => res.json())
  .then((data) => console.log(data))
  .catch((error) => console.error(&#8220;失敗しました&#8221;, error));
</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://example.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">())</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">catch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">error</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">失敗しました</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">error</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<ul class="wp-block-list">
<li><code>.then()</code> は「成功したらこれをしてね」</li>



<li><code>.catch()</code> は「失敗したらこれをしてね」</li>
</ul>



<p>このように、<strong><span class="marker">Promiseの結果に対して、処理を“つなげて”書ける</span></strong>のが特徴です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">なぜ .then() / .catch() が使えるの？</span></h3>



<p>それは、返り値が「Promise型」だからです。</p>



<p>JavaScriptでは、<span class="marker"><code>.then()</code> や <code>.catch()</code> は <strong>Promise型の値にしか使えません</strong></span>。</p>



<p>&#x2705; <code>.then()</code> を使えるのは Promise型 だけです。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const result = fetch(&#8220;https://example.com&#8221;);
console.log(result); // → Promise { &lt;pending> }</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://example.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// → Promise { &lt;pending&gt; }</span></span></code></pre></div>



<p>&#x274c; Promise を返さない関数に .then() は使えない</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>function greet() {
  return &#8220;こんにちは&#8221;; // ただの文字列
}
greet().then((msg) => console.log(msg)); // &#x274c; エラー！</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">greet</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">こんにちは</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ただの文字列</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #88C0D0">greet</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">msg</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">msg</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// &#x274c; エラー！</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">返り値を見ずに「Promise型かどうか」を見分けるには？</span></h3>



<ol start="1" class="wp-block-list">
<li><strong>関数の仕様を調べる</strong>
<ul class="wp-block-list">
<li>公式ドキュメントや型定義に <code>Promise</code> と書かれていれば、Promise型の返り値です。</li>



<li>例：<code>fetch()</code> や <code>axios.get()</code> は Promise を返すと明記されています。</li>
</ul>
</li>



<li><strong>関数の型アノテーション（TypeScript）</strong>
<ul class="wp-block-list">
<li><code>function getData(): Promise&lt;string&gt; { ... }</code> のように <code>Promise&lt;型&gt;</code> と書かれていれば、明確に Promise型です。</li>
</ul>
</li>



<li><strong>返り値に .then() を使ってみる（最終手段）</strong>
<ul class="wp-block-list">
<li>実際に <code>.then()</code> をつけて動作するか試すと、Promise型かどうかがわかります（ただし危険なので1と2が推奨）</li>
</ul>
</li>
</ol>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image aligncenter"><img decoding="async" src="https://www24.a8.net/svt/bgt?aid=230520456030&amp;wid=001&amp;eno=01&amp;mid=s00000016188001099000&amp;mc=1" alt=""/></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">async / await とは？</span></h2>



<p><code>.then()</code> だけだと、処理が長くなると読みづらくなります。 それをもっと“ふつうの順番”っぽく書けるようにしたのが、<code>async</code> と <code>await</code> です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>async function loadData() {
  const res = await fetch(&#8220;https://example.com&#8221;);
  const data = await res.json();
  console.log(data);
}</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">loadData</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://example.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<ul class="wp-block-list">
<li><code>async</code> は「この関数は非同期（Promise）を使うよ」と宣言するもの</li>



<li><code>await</code> は「この処理が終わるまで“ちょっと待って”ね」という意味</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc9">注意：await は async がついた関数の中でしか使えない</span></h3>



<p><code>await</code> は、「Promiseの結果を待つ」キーワードですが、 それ単体では使えず、<strong><span class="marker">必ず <code>async</code> 関数の中で使う必要がある</span></strong>と覚えておきましょう。</p>



<p>&#x2705; 正しい書き方（async 関数の中で await を使う）</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>async function getData() {
  const result = await fetch(&#8220;https://example.com&#8221;);
  const json = await result.json();
  console.log(json);
}</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">getData</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://example.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">json</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">json</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p> &#x274c; エラーになる例（関数の外で await を使っている）</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const result = await fetch(&#8220;https://example.com&#8221;);</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://example.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">try { &#8230; } catch { &#8230; } とは？</span></h2>



<p>非同期処理をしていると、失敗することもあります。 たとえば、サーバーが止まっていたり、ネットがつながっていなかったりする状況です。</p>



<p>そんなときに、エラーが出てプログラムが止まらないようにするための仕組みが、 <code>try</code> と <code>catch</code> です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>async function getData() {
  try {
    const res = await fetch(&#8220;https://example.com&#8221;);
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error(&#8220;エラーが起きました:&#8221;, err);
  }
}</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">getData</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">try</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://example.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">catch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">エラーが起きました:</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<ul class="wp-block-list">
<li><code>try</code> の中に「失敗するかもしれない処理」を書く</li>



<li><code>catch</code> の中に「失敗したときにどうするか」を書く</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image aligncenter"><img decoding="async" src="https://www26.a8.net/svt/bgt?aid=250611125635&amp;wid=001&amp;eno=01&amp;mid=s00000001817008016000&amp;mc=1" alt=""/></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc11">.catch() と try/catch の違いは？</span></h2>



<p>どちらも「エラー処理」ですが、使い方が違います。</p>



<p><code>.then()</code> を使うなら <code>.catch()</code> を、 <code>await</code> を使うなら <code>try/catch</code> を使うのが基本の形です。</p>



<figure class="wp-block-table is-style-stripes"><table class="has-fixed-layout"><thead><tr><th>項目</th><th>使える場面</th><th>処理の書き方</th></tr></thead><tbody><tr><td><code>.catch()</code></td><td><code>.then()</code> で書く場合</td><td><code>.then().catch()</code></td></tr><tr><td><code>try/catch</code></td><td><code>async/await</code> で書く場合</td><td><code>try { await ... } catch {}</code></td></tr></tbody></table></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc12">async/await・.then()/.catch()・try/catch を全部使った例</span></h2>



<p>下記のコードは、<strong>Reactを使って非同期処理の動作を試すサンプルアプリ</strong>です。<br>簡単にいうと、「ユーザー情報を取得 → その名前を使ってあいさつ文を表示」する処理です。</p>



<p><strong>言語</strong>：JavaScript<br><strong>ライブラリ</strong>：React</p>



<h3 class="wp-block-heading"><span id="toc13">正常終了</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>import React, { useEffect, useState } from &#8220;react&#8221;;
function App() {
  const [msg, setMsg] = useState(&#8220;&#8221;);
  useEffect(() => {
    (async () => {
      try {
        const res = await mockFetchUser();
        const data = await res.json();
        someAsyncOperation(data)
          .then(setMsg)
          .catch((e) => setMsg(&#8220;中のエラー: &#8221; + e));
      } catch (e) {
        setMsg(&#8220;fetchのエラー: &#8221; + e);
      }
    })();
  }, []);
  return (
    &lt;div>
      &lt;h1>React 非同期処理テスト&lt;/h1>
      &lt;p>{msg}&lt;/p>
    &lt;/div>
  );
}
const mockFetchUser = () =>
  Promise.resolve({ json: () => Promise.resolve({ name: &#8220;太郎さん&#8221; }) });
const someAsyncOperation = (d) =>
  d.name
    ? Promise.resolve(&#8220;こんにちは、&#8221; + d.name)
    : Promise.reject(&#8220;名前がありません&#8221;);
export default App;
</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">React</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">useEffect</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">useState</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">react</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">App</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9">msg</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setMsg</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">useEffect</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    (</span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">try</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mockFetchUser</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">someAsyncOperation</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">then</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">setMsg</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">catch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">setMsg</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">中のエラー: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">catch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">setMsg</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">fetchのエラー: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span><span style="color: #D8DEE9FF"> [])</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;h1&gt;</span><span style="color: #D8DEE9FF">React 非同期処理テスト</span><span style="color: #81A1C1">&lt;/h1&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;p&gt;{</span><span style="color: #D8DEE9">msg</span><span style="color: #81A1C1">}&lt;/p&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mockFetchUser</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">Promise</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">resolve</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">json</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Promise</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">resolve</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">太郎さん</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">someAsyncOperation</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">d</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">d</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">name</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Promise</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">resolve</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">こんにちは、</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">d</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">name</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Promise</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">reject</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">名前がありません</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">App</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p>&#x2705; 表示結果<br><code>mockFetchUser</code> 関数 → <code>res.json()</code> → <code>data.name</code> が <code>"太郎さん"</code> のため、<br><code>someAsyncOperation</code> の結果「こんにちは、太郎さん」が画面に表示される</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img loading="lazy" decoding="async" width="954" height="256" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.10.10.png" alt="async/awaitとPromiseの違いとは？" class="wp-image-3472" style="border-width:1px;width:533px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.10.10.png 954w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.10.10-300x81.png 300w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.10.10-768x206.png 768w" sizes="auto, (max-width: 954px) 100vw, 954px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc14">.catch() でエラー表示</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>// 省略&#8230;
const mockFetchUser = () =>
  Promise.resolve({ json: () => Promise.resolve({ name: &#8220;&#8221; }) });
// 省略&#8230;</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// 省略...</span></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mockFetchUser</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">Promise</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">resolve</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">json</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Promise</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">resolve</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// 省略...</span></span></code></pre></div>



<p>&#x2705; 表示結果<br><code>mockFetchUser</code> 関数 → <code>res.json()</code> → <code>data.name</code> が <code>undefined</code> または false のため、<br><code>someAsyncOperation</code> は <code>reject("名前がありません")</code> を返し、<br><code>.catch()</code> により「中のエラー: 名前がありません」が画面に表示される。</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img loading="lazy" decoding="async" width="946" height="258" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.10.42.png" alt="async/awaitとPromiseの違いとは？" class="wp-image-3474" style="border-width:1px;width:528px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.10.42.png 946w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.10.42-300x82.png 300w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.10.42-768x209.png 768w" sizes="auto, (max-width: 946px) 100vw, 946px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc15">例外発生のため try/catch でエラー表示</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>// 省略&#8230;
const mockFetchUser = () => Promise.reject(&#8220;ネットワークエラー&#8221;);
// 省略&#8230;</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// 省略...</span></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mockFetchUser</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Promise</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">reject</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ネットワークエラー</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// 省略...</span></span></code></pre></div>



<p>&#x2705; 表示結果<br><code>mockFetchUser</code> 関数が <code>reject("ネットワークエラー")</code> を返したため、<br><code>await mockFetchUser()</code> で例外が発生し、<br><code>catch</code> により「fetchのエラー: ネットワークエラー」が画面に表示される。</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img loading="lazy" decoding="async" width="942" height="220" src="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.14.13.png" alt="async/awaitとPromiseの違いとは？" class="wp-image-3477" style="border-width:1px;width:527px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.14.13.png 942w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.14.13-300x70.png 300w, https://it-bokenki.com/wp-content/uploads/2025/06/スクリーンショット-2025-06-16-14.14.13-768x179.png 768w" sizes="auto, (max-width: 942px) 100vw, 942px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-embed is-type-wp-embed is-provider-it wp-block-embed-it"><div class="wp-block-embed__wrapper">
<a href="https://it-bokenki.com/2025/06/14/status/" title="404？500? ステータスコードとは？よく見るコード厳選まとめ" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-3-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-3-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-3-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-3-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">404？500? ステータスコードとは？よく見るコード厳選まとめ</div><div class="blogcard-snippet internal-blogcard-snippet">開発エンジニアが現場でよく使うHTTPステータスコードを、意味・原因・使われる場面とともにわかりやすく解説！</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div></figure>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div><p>The post <a href="https://it-bokenki.com/2025/06/16/async-await-promise-basic/">async/awaitとPromiseの違いとは？</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/06/16/async-await-promise-basic/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Zodの .object() とセットで使うバリデーション構文まとめ</title>
		<link>https://it-bokenki.com/2025/06/16/zod-object-validation/</link>
					<comments>https://it-bokenki.com/2025/06/16/zod-object-validation/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Mon, 16 Jun 2025 03:57:31 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<category><![CDATA[Zod]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=3373</guid>

					<description><![CDATA[<p>でじぼうです。 Zodを使ったバリデーションで一番よく出てくるのが .object()でも実際の現場では、それだけでは足りないことが多いです。 この記事では .object() と一緒によく使う構文だけにしぼって、未経験 [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/06/16/zod-object-validation/">Zodの .object() とセットで使うバリデーション構文まとめ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>でじぼうです。</p>



<p>Zodを使ったバリデーションで一番よく出てくるのが <code>.object()</code><br>でも実際の現場では、それ<strong>だけでは足りないことが多い</strong>です。</p>



<p>この記事では <code>.object()</code> と一緒に<strong>よく使う構文だけ</strong>にしぼって、未経験でもわかるように解説します！</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="でじぼう" class="speech-icon-image"/></figure><div class="speech-name">でじぼう</div></div><div class="speech-balloon">
<p>この記事は下記の方がおすすめ！<br></p>



<ul class="wp-block-list">
<li style="font-size:15px">Zodってなに？</li>



<li style="font-size:15px">.object() ってなに？</li>



<li style="font-size:15px">よく使われる構文の違いが知りたい</li>
</ul>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NZROH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=230528653907&#038;wid=001&#038;eno=01&#038;mid=s00000023513004030000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=3T911P+F006GI+51FE+NZROH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=3T911P+F006GI+51FE+NWRNM">Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち</a></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-default">
<a href="https://it-bokenki.com/2025/06/16/f12-network-tab/" title="【初心者向け】Networkタブの使い方をやさしく解説｜APIの見方や通信トラブル対処まで" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-8-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-8-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-8-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-8-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【初心者向け】Networkタブの使い方をやさしく解説｜APIの見方や通信トラブル対処まで</div><div class="blogcard-snippet internal-blogcard-snippet">F12キーで開く「Networkタブ」の基本を初心者向けに解説。通信状況の確認、APIのエラー調査、画面が動かない原因の特定に役立つ見方を紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc1">Zodとは？</span></h2>



<p>Zodは、TypeScriptで「入力ルール（バリデーション）」を簡単に定義できるライブラリです。</p>



<ul class="wp-block-list">
<li>形式チェック（文字列・数値・メールなど）</li>



<li>必須・任意の設定</li>



<li>条件付きのチェック</li>
</ul>



<p>などが、<strong>読みやすい構文で書ける</strong>のが特徴です。<br>より詳細は下記のブログをご確認ください。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-default">
<a href="https://it-bokenki.com/2025/06/11/zod/" title="Zodとは？React Hook Formとの連携でバリデーション実装" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-1-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-1-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-1-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-1-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Zodとは？React Hook Formとの連携でバリデーション実装</div><div class="blogcard-snippet internal-blogcard-snippet">TypeScriptで使えるバリデーションライブラリ「Zod」の基本と、React Hook Formとの連携方法を解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">.object()とは？</span></h2>



<p>フォーム全体の「入力ルール」をまとめて定義できる、Zodの土台です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const schema = z.object({
  name: z.string(),
  email: z.string().email(),
});</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">schema</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">email</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">email</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p><span class="badge-green">コードの意味</span></p>



<ul class="wp-block-list">
<li><code>name</code> は文字列の入力が必要（必須）</li>



<li><code>email</code> はメール形式での入力が必要（必須）</li>
</ul>



<p>このように、<code>.object()</code> を使うことで<strong>複数の入力項目を1つのスキーマとしてまとめる</strong>ことができます。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">一緒によく使う構文一覧【目的別】</span></h2>



<figure class="wp-block-table is-style-stripes"><table class="has-fixed-layout"><thead><tr><th>構文</th><th>できること</th><th>使用頻度</th></tr></thead><tbody><tr><td><code><span class="marker">.superRefine()</span></code></td><td>複数項目をまとめてチェック</td><td>◎ よく使う</td></tr><tr><td><code><span class="marker">.partial()</span></code><br>（パーシャル）</td><td>全ての項目を「入力なしでもOK」に</td><td>◎ よく使う</td></tr><tr><td><code><span class="marker">.merge()</span></code></td><td>スキーマ同士を合体</td><td>○ 時々使う</td></tr><tr><td><code><span class="marker">.extend()</span></code></td><td>既存のスキーマに追加する</td><td>○ 時々使う</td></tr><tr><td><code><span class="marker">.pick()</span></code></td><td>一部の項目だけ取り出す</td><td>○ 時々使う</td></tr><tr><td><code><span class="marker">.omit()</span></code></td><td>一部の項目を除外する</td><td>○ 時々使う</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">.superRefine()とは？</span></h2>



<p>複数項目を「まとめてチェック」したいときに利用します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const schema = z.object({
  password: z.string(),
  confirm: z.string(),
}).superRefine((data, ctx) => {
  if (data.password !== data.confirm) {
    ctx.addIssue({
      path: [&#8220;confirm&#8221;],
      message: &#8220;パスワードが一致しません&#8221;,
      code: z.ZodIssueCode.custom,
    });
  }
});</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">schema</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">password</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">confirm</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">superRefine</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ctx</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">password</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">confirm</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">ctx</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">addIssue</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">path</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> [</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">confirm</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">]</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">message</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">パスワードが一致しません</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">code</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">ZodIssueCode</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">custom</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p><span class="badge-green">コードの意味</span></p>



<p>&#x1f4d8; <code>data</code> とは？</p>



<ul class="wp-block-list">
<li><code>z.object({...})</code> に渡したすべての入力値（name, email など）が入っているオブジェクトのことを指す</li>



<li>React Hook Form の <code>getValues()</code> と同じ構造</li>
</ul>



<p>&#x1f4d8; <code>ctx.addIssue()</code> とは？</p>



<ul class="wp-block-list">
<li>条件に合致した場合に、「この項目にエラーがある」と Zod に伝える関数</li>



<li><code>path: ["confirm"]</code> と指定すれば、<code>confirm</code> にエラーメッセージが表示できる</li>



<li><code>code: z.ZodIssueCode.custom</code> は「独自ルールによるエラー」であることを示す<br></li>
</ul>



<p>&#x1f4d8;コード全体の意味</p>



<ul class="wp-block-list">
<li><code>.superRefine()</code> は、バリデーションの<strong>対象全体（objectの中身）にアクセスできる</strong>関数</li>



<li><code>password</code> と <code>confirm</code> が一致していなければ、<code>confirm</code> 項目にエラーを追加</li>
</ul>



<p><span class="badge-yellow">よくある使い方</span></p>



<ul class="wp-block-list">
<li>パスワード確認</li>



<li>日付の前後関係</li>



<li>条件付き入力のバリデーション</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc5">.partial()とは？</span></h2>



<p>全部「任意入力」にするときに利用します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const schema = z.object({
  title: z.string(),
  content: z.string(),
}).partial();</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">schema</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">title</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">content</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">partial</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p><span class="badge-green">コードの意味</span></p>



<ul class="wp-block-list">
<li><code>title</code> も <code>content</code> も、<strong>未入力でもエラーにならない</strong></li>
</ul>



<p><span class="badge-yellow">よくある使い方</span></p>



<ul class="wp-block-list">
<li>入力フォームで、<strong>どれか1つだけ更新</strong>したいとき（プロフィール編集など）</li>



<li>一部だけ更新するような画面で、<strong>全項目が必須でないとき</strong></li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">.optional() でも同じ意味になる</span></h3>



<p>下記の記載は、上記の<code><code>.partial()</code></code>で定義した場合と、結果はまったく同じになります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const schema = z.object({
  title: z.string().optional(),
  content: z.string().optional(),
});
</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">schema</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">title</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">optional</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">content</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">optional</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">では .partial() を使うメリットは？</span></h3>



<ul class="wp-block-list">
<li>プロパティがたくさんあるときに <strong>1つずつ <code>.optional()</code> を書かなくて済む</strong></li>



<li>スキーマを再利用する際に、<strong>必須版と任意版を簡単に切り替えられる</strong></li>
</ul>



<p>&#x2705; <code>.optional()</code> を個別に書いてもOK<br>&#x2705; <code>.partial()</code> は <strong>全部を一括で optional にしたいとき</strong>に便利！</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">.merge()とは？</span></h2>



<p>共通ルールと追加ルールを「合体する」ときに利用します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const base = z.object({ id: z.string() });
const detail = z.object({ name: z.string() });

const schema = base.merge(detail);</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">base</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">id</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">detail</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">schema</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">base</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">merge</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">detail</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p><span class="badge-green">コードの意味</span></p>



<ul class="wp-block-list">
<li><code>id</code> と <code>name</code> の両方を含んだ1つのスキーマを作る</li>
</ul>



<p><span class="badge-yellow">よくある使い方</span></p>



<ul class="wp-block-list">
<li>IDだけで定義した共通スキーマに、画面ごとの入力項目（詳細）を足したいとき</li>



<li><strong>共通部分と画面ごとの違いを分けて管理</strong>したいとき（保守性アップ）</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">.extend()とは？</span></h2>



<p>既存のスキーマに追加するときに利用します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const user = z.object({ name: z.string() });
const extended = user.extend({ age: z.number() });</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">extended</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">user</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">extend</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">age</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">number</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p><span class="badge-green">コードの意味</span></p>



<ul class="wp-block-list">
<li><code>user</code> に <code>age</code> を追加した新しいスキーマを作る</li>
</ul>



<p><span class="badge-yellow">よくある使い方</span></p>



<ul class="wp-block-list">
<li><strong>もとのスキーマを壊さずに</strong>追加したいとき（再利用性アップ）</li>



<li>複数画面で <code>user</code> は共通だが、年齢が必要なのは一部だけ…という場面など</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">.pick()とは？</span></h2>



<p>必要な項目だけ「取り出す」ときに利用します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const full = z.object({
  name: z.string(),
  email: z.string(),
  age: z.number(),
});

const nameOnly = full.pick({ name: true });</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">full</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">email</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">age</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">number</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nameOnly</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">full</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">pick</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p><span class="badge-green">コードの意味</span></p>



<ul class="wp-block-list">
<li><code>name</code> だけを含むスキーマを作る</li>
</ul>



<p><span class="badge-yellow">よくある使い方</span></p>



<ul class="wp-block-list">
<li>一覧画面などで、<strong>一部の情報だけ使いたいとき</strong></li>



<li>画面に表示するフィールドを限定したいとき</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc11">.omit()とは？</span></h2>



<p>不要な項目だけ「除外する」ときに利用します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>const full = z.object({
  name: z.string(),
  email: z.string(),
  age: z.number(),
});

const noEmail = full.omit({ email: true });</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">full</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">email</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">age</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">number</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">noEmail</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">full</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">omit</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">email</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p><span class="badge-green">コードの意味</span></p>



<ul class="wp-block-list">
<li><code>email</code> を除外したスキーマを作る</li>
</ul>



<p><span class="badge-yellow">よくある使い方</span></p>



<ul class="wp-block-list">
<li>セキュリティ上、<strong>特定の項目を外したいとき</strong>（たとえばパスワードなど）</li>



<li>APIレスポンスで<strong>不要な情報を含めたくないとき</strong></li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc12">補足：.refine() は .object() の中で「項目ごと」に使う</span></h2>



<p><code>.refine()</code> は<strong>単体の項目</strong>に対して使い、複数項目にまたがるときは <code>.superRefine()</code> を使います。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>z.object({
  username: z.string().refine(val => val !== &#8220;admin&#8221;, {
    message: &#8220;admin は使えません&#8221;,
  }),
});</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">username</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">refine</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">val</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">val</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!==</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">message</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin は使えません</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p><span class="badge-green">コードの意味</span></p>



<ul class="wp-block-list">
<li><code>username</code> が &#8220;admin&#8221; だったらエラーになる、という<strong>1つの項目に対する条件</strong></li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-default">
<a href="https://it-bokenki.com/2025/06/16/f12-network-tab/" title="【初心者向け】Networkタブの使い方をやさしく解説｜APIの見方や通信トラブル対処まで" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-8-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-8-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-8-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-8-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【初心者向け】Networkタブの使い方をやさしく解説｜APIの見方や通信トラブル対処まで</div><div class="blogcard-snippet internal-blogcard-snippet">F12キーで開く「Networkタブ」の基本を初心者向けに解説。通信状況の確認、APIのエラー調査、画面が動かない原因の特定に役立つ見方を紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div><p>The post <a href="https://it-bokenki.com/2025/06/16/zod-object-validation/">Zodの .object() とセットで使うバリデーション構文まとめ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/06/16/zod-object-validation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
