「TS2322が消えない」「TS7006でビルドが落ちる」「TS2532で延々と ! を付けて回ってる」――TypeScriptを書いていれば誰もが一度は通る道です。本記事は TypeScript 5.x を前提に、現場で本当に頻出するエラー 30+パターン を「エラーコード→再現コード(Before)→修正コード(After)→なぜ起きるか」の4点セットで一気に潰していく実践リファレンスです。
すべてのコードは strict: true / target: ES2022 / moduleResolution: bundler 環境で動作検証済み。コピペでそのまま動かして手で覚えてください。
- 1. TS2322 Type ‘X’ is not assignable to type ‘Y’
- 2. TS2345 Argument of type ‘X’ is not assignable to parameter of type ‘Y’
- 3. TS7006 Parameter implicitly has an ‘any’ type
- 4. TS2339 Property ‘X’ does not exist on type ‘Y’
- 5. TS2304 Cannot find name ‘X’
- 6. TS2532 Object is possibly ‘undefined’
- 7. TS2531 Object is possibly ‘null’
- 8. TS18046 ‘X’ is of type ‘unknown’
- 9. TS2740 Type ‘X’ is missing the following properties from type ‘Y’
- 10. TS2741 Property ‘X’ is missing in type ‘Y’ but required in type ‘Z’
- 11. TS2769 No overload matches this call
- 12. TS2367 This comparison appears to be unintentional
- 13. TS2454 Variable ‘X’ is used before being assigned
- 14. TS2705 An async function or method … must have a valid awaitable return type
- 15. TS18047 ‘X’ is possibly ‘null’
- 16. TS2554 Expected N arguments, but got M
- 17. TS2349 This expression is not callable
- 18. TS2353 Object literal may only specify known properties
- 19. TS2786 ‘X’ cannot be used as a JSX component
- 20. TS6133 ‘X’ is declared but its value is never read
- 21. TS17004 Cannot use JSX unless the ‘–jsx’ flag is provided
- 22. TS2305 Module ‘X’ has no exported member ‘Y’
- 23. TS2307 Cannot find module ‘X’ or its corresponding type declarations
- 24. TS2742 The inferred type of ‘X’ cannot be named without a reference
- 25. TS1259 Module ‘X’ can only be default-imported using the ‘esModuleInterop’ flag
- 26. TS6133 unused variable(再掲・実務パターン)
- 27. TS2802 Type ‘X’ can only be iterated through when using the ‘–downlevelIteration’ flag
- 28. TS5023 Unknown compiler option ‘X’
- 29. TS1192 Module ‘X’ has no default export
- 30. TS2304 Cannot find name(環境変数)
- 31. TS2589 Type instantiation is excessively deep and possibly infinite
- 32. tsconfig関連エラー総まとめ
- 33. moduleResolution: bundler 移行時のエラー対処
- 34. 補助: ESLint/TypeScript Eslint 連携エラー
- エラーをそもそも減らすための7つの設計指針
- satisfies の実用パターン
- 1日でエラー耐性を底上げする学習ルート
- よくある質問(FAQ)
- まとめ
1. TS2322 Type ‘X’ is not assignable to type ‘Y’
もっともよく見るエラー。代入先の型と代入元の型が一致しない、または広すぎる/狭すぎる時に発生します。
1-1. プリミティブの不一致
Before:
// ❌ TS2322: Type 'string' is not assignable to type 'number'.
const age: number = "30";
After:
// ✅ 型を合わせるか、変換する
const age: number = 30;
// 文字列から数値にしたい場合
const ageFromInput: number = Number("30");
1-2. ユニオン型に対するリテラル割り当て
Before:
type Status = "idle" | "loading" | "success" | "error";
// ❌ TS2322: Type 'string' is not assignable to type 'Status'.
let s: Status = "loding"; // タイポ
After:
type Status = "idle" | "loading" | "success" | "error";
// ✅ const assertion で誤入力を即時検知
const s = "loading" as const satisfies Status;
1-3. 戻り値型の不一致(関数)
Before:
// ❌ TS2322: Type 'string' is not assignable to type 'number'.
const getId = (): number => {
return "u-001";
};
After:
// ✅ 戻り値型を実態に合わせる(またはロジック側を直す)
const getId = (): string => {
return "u-001";
};
2. TS2345 Argument of type ‘X’ is not assignable to parameter of type ‘Y’
関数呼び出しの引数で型が合わない時に出ます。TS2322の「引数版」と覚えてOK。
2-1. 引数の型が緩すぎる
Before:
function greet(name: string) {
return `Hello, ${name.toUpperCase()}`;
}
// ❌ TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
greet(123);
After:
function greet(name: string) {
return `Hello, ${name.toUpperCase()}`;
}
// ✅ 文字列化して渡す
greet(String(123));
2-2. オブジェクト引数の余剰プロパティ
Before:
type User = { id: string; name: string };
function save(u: User) { /* ... */ }
// ❌ TS2345 + TS2353: 'role' は User に存在しない
save({ id: "1", name: "yui", role: "admin" });
After:
type User = { id: string; name: string; role?: "admin" | "user" };
function save(u: User) { /* ... */ }
// ✅ User側にroleを足すか、別の型に分離する
save({ id: "1", name: "yui", role: "admin" });
3. TS7006 Parameter implicitly has an ‘any’ type
noImplicitAny(strict 配下で自動有効)で、関数パラメータの型注釈忘れに出るエラーです。
3-1. コールバックの引数型忘れ
Before:
// ❌ TS7006: Parameter 'item' implicitly has an 'any' type.
const formatItems = (items) => items.map((item) => item.name);
After:
type Item = { id: string; name: string };
// ✅ 明示的に型を付ける
const formatItems = (items: Item[]): string[] =>
items.map((item) => item.name);
3-2. イベントハンドラの引数型忘れ(React)
Before:
// ❌ TS7006: Parameter 'e' implicitly has an 'any' type.
const onChange = (e) => console.log(e.target.value);
After:
import type { ChangeEvent } from "react";
// ✅ React.ChangeEventで型を明示
const onChange = (e: ChangeEvent<HTMLInputElement>) =>
console.log(e.target.value);
4. TS2339 Property ‘X’ does not exist on type ‘Y’
型にないプロパティへアクセスした時のエラー。実は型定義が古い、または型を絞り込めていないことが原因のことが多いです。
4-1. ユニオン型での絞り込み不足
Before:
type ApiResult =
| { ok: true; data: string }
| { ok: false; error: string };
function show(res: ApiResult) {
// ❌ TS2339: Property 'data' does not exist on type ...
console.log(res.data);
}
After:
type ApiResult =
| { ok: true; data: string }
| { ok: false; error: string };
function show(res: ApiResult) {
// ✅ 判別可能ユニオンで絞り込んでからアクセス
if (res.ok) {
console.log(res.data);
} else {
console.error(res.error);
}
}
4-2. window 拡張のグローバル宣言
Before:
// ❌ TS2339: Property 'gtag' does not exist on type 'Window & typeof globalThis'.
window.gtag("event", "click");
After:
// global.d.ts などで宣言マージ
declare global {
interface Window {
gtag: (cmd: string, ...args: unknown[]) => void;
}
}
export {};
// ✅ 以降は型エラーなくアクセス可能
window.gtag("event", "click");
5. TS2304 Cannot find name ‘X’
その識別子が見つからない(=スコープに存在しない)エラー。importミスかtsconfigのlib不足が大半です。
5-1. importの書き忘れ
Before:
// ❌ TS2304: Cannot find name 'useState'.
const [count, setCount] = useState(0);
After:
// ✅ react から useState をインポート
import { useState } from "react";
const [count, setCount] = useState(0);
5-2. DOM API が見つからない
Before:
// ❌ TS2304: Cannot find name 'document'.
const root = document.getElementById("root");
After(tsconfig.json):
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"]
}
}
6. TS2532 Object is possibly ‘undefined’
strictNullChecks下で、undefinedになりうる値へアクセスした時のエラー。! で潰すのは最終手段で、原則は絞り込みで対処します。
6-1. 配列要素アクセス
Before:
const users = ["alice", "bob"];
// noUncheckedIndexedAccess: true の場合
// ❌ TS2532: Object is possibly 'undefined'.
console.log(users[2].toUpperCase());
After:
const users = ["alice", "bob"];
const first = users[0];
// ✅ オプショナルチェイニング+デフォルト値
console.log(first?.toUpperCase() ?? "no user");
6-2. オプショナルプロパティ
Before:
type User = { name: string; address?: { city: string } };
function showCity(u: User) {
// ❌ TS2532: Object is possibly 'undefined'.
return u.address.city;
}
After:
type User = { name: string; address?: { city: string } };
function showCity(u: User) {
// ✅ Optional Chaining で安全にアクセス
return u.address?.city ?? "(unknown)";
}
7. TS2531 Object is possibly ‘null’
TS2532のnull版。DOM API で頻発します。
7-1. getElementById の null チェック
Before:
// ❌ TS2531: Object is possibly 'null'.
const el = document.getElementById("app");
el.innerHTML = "hello";
After:
// ✅ 存在チェック → 早期return
const el = document.getElementById("app");
if (!el) throw new Error("#app not found");
el.innerHTML = "hello";
7-2. useRef の current が null
Before:
import { useRef, useEffect } from "react";
function Focus() {
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
// ❌ TS2531: Object is possibly 'null'.
ref.current.focus();
}, []);
return <input ref={ref} />;
}
After:
import { useRef, useEffect } from "react";
function Focus() {
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
// ✅ null チェック後にメソッド呼び出し
ref.current?.focus();
}, []);
return <input ref={ref} />;
}
8. TS18046 ‘X’ is of type ‘unknown’
catch句のerror、JSON.parseの戻り値、APIレスポンスなど、安全に型が決まらないものは unknown になります。直接プロパティアクセスできません。
8-1. catch句のerror
Before:
try {
await fetch("/api/x");
} catch (e) {
// ❌ TS18046: 'e' is of type 'unknown'.
console.error(e.message);
}
After:
try {
await fetch("/api/x");
} catch (e) {
// ✅ instanceof で絞り込む
if (e instanceof Error) {
console.error(e.message);
} else {
console.error("unknown error", e);
}
}
8-2. JSON.parse の結果
Before:
const raw = '{"id":1,"name":"alice"}';
const data: unknown = JSON.parse(raw);
// ❌ TS18046: 'data' is of type 'unknown'.
console.log(data.name);
After:
import { z } from "zod";
const UserSchema = z.object({ id: z.number(), name: z.string() });
const raw = '{"id":1,"name":"alice"}';
// ✅ Zodで実行時バリデーション+型導出
const data = UserSchema.parse(JSON.parse(raw));
console.log(data.name); // string と確定
9. TS2740 Type ‘X’ is missing the following properties from type ‘Y’
必須プロパティが大量に足りない時のエラー。空オブジェクトに対する初期化でよく出ます。
9-1. 必須プロパティの抜け
Before:
type Config = { host: string; port: number; secure: boolean };
// ❌ TS2740: Type '{}' is missing the following properties...
const c: Config = {};
After:
type Config = { host: string; port: number; secure: boolean };
// ✅ すべての必須プロパティを与える
const c: Config = { host: "localhost", port: 5432, secure: false };
9-2. デフォルト値のためのPartial
Before:
type Config = { host: string; port: number; secure: boolean };
// ❌ 初期値だけ作って後でマージしたいのに必須が辛い
const defaults: Config = { host: "localhost" }; // TS2740
After:
type Config = { host: string; port: number; secure: boolean };
// ✅ Partial<T> で「全プロパティ任意」化
const defaults: Partial<Config> = { host: "localhost" };
const merged: Config = { port: 5432, secure: false, ...defaults };
10. TS2741 Property ‘X’ is missing in type ‘Y’ but required in type ‘Z’
TS2740のピンポイント版。1個だけ足りない時に出ます。
10-1. 1プロパティ抜け
Before:
type Props = { title: string; description: string };
// ❌ TS2741: Property 'description' is missing
const p: Props = { title: "Hello" };
After:
type Props = { title: string; description: string };
// ✅ 足すか、 description?: string に変更する
const p: Props = { title: "Hello", description: "" };
11. TS2769 No overload matches this call
オーバーロードのある関数(setTimeout、addEventListener、JSXコンポーネント等)で、引数の組み合わせがどのシグネチャにも合致しない時のエラー。
11-1. setTimeout の引数ミス
Before:
// ❌ TS2769: No overload matches this call.
setTimeout("console.log('hi')", 1000); // 文字列はNG
After:
// ✅ 関数(コールバック)を渡す
setTimeout(() => console.log("hi"), 1000);
11-2. addEventListener 型ミス
Before:
const btn = document.querySelector("button")!;
// ❌ TS2769: No overload matches this call.
btn.addEventListener("clicked", (e) => {}); // イベント名タイポ
After:
const btn = document.querySelector("button")!;
// ✅ 正しいイベント名で文字列リテラル型と一致させる
btn.addEventListener("click", (e: MouseEvent) => {
console.log(e.clientX);
});
12. TS2367 This comparison appears to be unintentional
比較の両辺の型に重なりがないと出る親切エラー。バグ予備軍を検出してくれます。
12-1. 型が重ならない比較
Before:
type Role = "admin" | "user";
function isOwner(role: Role) {
// ❌ TS2367: This condition will always return 'false'.
return role === "owner";
}
After:
type Role = "admin" | "user" | "owner";
function isOwner(role: Role) {
// ✅ Role に "owner" を加える、または比較自体を見直す
return role === "owner";
}
13. TS2454 Variable ‘X’ is used before being assigned
宣言だけして代入していない変数を使った時のエラー。条件分岐の中で代入する書き方で発生しがちです。
13-1. 条件分岐で漏れた代入
Before:
let result: string;
const flag = Math.random() > 0.5;
if (flag) {
result = "A";
}
// ❌ TS2454: Variable 'result' is used before being assigned.
console.log(result);
After:
// ✅ 初期値を必ず持たせる、または else を埋める
let result: string = "default";
const flag = Math.random() > 0.5;
if (flag) result = "A";
else result = "B";
console.log(result);
14. TS2705 An async function or method … must have a valid awaitable return type
async関数の戻り値型が Promise<T> 形式になっていない時のエラー(主に古いlibや誤った型指定)。
14-1. async関数の戻り値型ミス
Before:
// ❌ TS2705 / TS1064 系: async は Promise を返す必要がある
async function getName(): string {
return "alice";
}
After:
// ✅ Promise<T> を返す
async function getName(): Promise<string> {
return "alice";
}
15. TS18047 ‘X’ is possibly ‘null’
TS2531系のうち、メソッド呼び出しではなく値そのものへのアクセスで出るバージョン。
15-1. localStorage の値
Before:
const token = localStorage.getItem("token");
// ❌ TS18047: 'token' is possibly 'null'.
const length: number = token.length;
After:
const token = localStorage.getItem("token");
// ✅ null合体で空文字フォールバック
const length: number = (token ?? "").length;
16. TS2554 Expected N arguments, but got M
関数の引数の数が違うエラー。多すぎる/少なすぎる両方で出ます。
16-1. 引数不足
Before:
function divide(a: number, b: number) {
return a / b;
}
// ❌ TS2554: Expected 2 arguments, but got 1.
divide(10);
After:
// ✅ デフォルト値か、オプショナル引数で柔軟に
function divide(a: number, b: number = 1) {
return a / b;
}
divide(10);
16-2. React onClick で過剰引数
Before:
const handleClick = (id: string) => console.log(id);
// ❌ TS2554: Expected 1 arguments, but got 0.
return <button onClick={handleClick}>Click</button>;
After:
const handleClick = (id: string) => console.log(id);
// ✅ アロー関数でラップし、必要な引数を束ねる
return <button onClick={() => handleClick("u-001")}>Click</button>;
17. TS2349 This expression is not callable
関数として呼び出せない値を呼んだ時。配列メソッドのチェーンミスでよく出ます。
17-1. ユニオン型に関数を持つもの
Before:
type Handler = ((s: string) => void) | string;
function run(h: Handler) {
// ❌ TS2349: This expression is not callable.
h("hi");
}
After:
type Handler = ((s: string) => void) | string;
function run(h: Handler) {
// ✅ typeof で絞り込む
if (typeof h === "function") {
h("hi");
} else {
console.log(h);
}
}
18. TS2353 Object literal may only specify known properties
余剰プロパティチェック。オブジェクトリテラルにだけ厳格に適用されます。
18-1. propsの余計なキー
Before:
type ButtonProps = { label: string; onClick: () => void };
// ❌ TS2353: 'color' does not exist in type 'ButtonProps'.
const props: ButtonProps = { label: "OK", onClick: () => {}, color: "red" };
After:
type ButtonProps = { label: string; onClick: () => void; color?: string };
// ✅ 型を拡張するか、不要なプロパティを削除
const props: ButtonProps = { label: "OK", onClick: () => {}, color: "red" };
19. TS2786 ‘X’ cannot be used as a JSX component
Reactコンポーネントが返している値が ReactNode と互換性がない時のエラー。version不一致でも出ます。
19-1. 配列を直接返している
Before:
// ❌ TS2786: Its return type 'string[]' is not a valid JSX element.
const List = (): string[] => ["a", "b", "c"];
After:
// ✅ JSX で包む、または Fragment を使う
const List = () => (
<>
{["a", "b", "c"].map((x) => (
<span key={x}>{x}</span>
))}
</>
);
19-2. @types/reactのバージョン不整合
Before:
# ❌ TS2786 が消えない時、@types/react と react のメジャー版がズレている
npm ls react @types/react
# react@19.0.0 / @types/react@18.x のような不一致
After:
# ✅ メジャー版を揃える
npm i -E @types/react@19 @types/react-dom@19
20. TS6133 ‘X’ is declared but its value is never read
未使用変数の警告。noUnusedLocals / noUnusedParameters で出ます。
20-1. 未使用の引数
Before:
// ❌ TS6133: 'err' is declared but its value is never read.
function safeParse(json: string, err: unknown) {
return JSON.parse(json);
}
After:
// ✅ アンダースコア接頭辞で「意図的に未使用」を表明
function safeParse(json: string, _err: unknown) {
return JSON.parse(json);
}
20-2. 未使用のimport
Before:
// ❌ TS6133: 'useMemo' is declared but its value is never read.
import { useState, useMemo } from "react";
const [v, setV] = useState(0);
After:
// ✅ 使わないものは消す(自動修正はESLintのno-unused-importsが便利)
import { useState } from "react";
const [v, setV] = useState(0);
21. TS17004 Cannot use JSX unless the ‘–jsx’ flag is provided
tsconfigの設定漏れ。Reactを書いていて初期段階に出ることが多い。
21-1. tsconfig.json の jsx 未設定
Before:
// ❌ TS17004: jsx の指定がない
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext"
}
}
After:
// ✅ React 17+は "react-jsx"(自動JSXランタイム)
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"jsx": "react-jsx",
"esModuleInterop": true
}
}
22. TS2305 Module ‘X’ has no exported member ‘Y’
名前付きエクスポートが存在しないモジュールから名前付きインポートしているエラー。
22-1. デフォルトエクスポートを名前付きで取ろうとした
Before:
// ❌ TS2305: Module '"react"' has no exported member 'React'.
import { React } from "react";
After:
// ✅ ReactはデフォルトExport
import React from "react";
// もしくは個別フックだけ取り出す
import { useState, useEffect } from "react";
23. TS2307 Cannot find module ‘X’ or its corresponding type declarations
パスかinstallミス。@types/xxx 未インストールが定番。
23-1. 型定義パッケージ未インストール
Before:
// ❌ TS2307: Cannot find module 'lodash' or its corresponding type declarations.
import _ from "lodash";
After:
# ✅ 型定義をdevDependencyで入れる
npm i -D @types/lodash
23-2. パスエイリアスの未設定
Before:
// ❌ TS2307: Cannot find module '@/lib/api' or its corresponding type declarations.
import { fetchUser } from "@/lib/api";
After(tsconfig.json):
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
24. TS2742 The inferred type of ‘X’ cannot be named without a reference
モノレポやライブラリ作者で頻発する厄介エラー。ライブラリの内部型に依存した推論が型宣言に出せない状態。
24-1. 明示的な型注釈で回避
Before:
// ❌ TS2742: The inferred type of 'createStore' cannot be named ...
import { create } from "zustand";
export const useStore = create((set) => ({
count: 0,
inc: () => set((s: { count: number }) => ({ count: s.count + 1 })),
}));
After:
// ✅ 戻り型を明示し、依存型をimport
import { create, type StoreApi } from "zustand";
type CounterStore = { count: number; inc: () => void };
export const useStore = create<CounterStore>((set) => ({
count: 0,
inc: () => set((s) => ({ count: s.count + 1 })),
}));
25. TS1259 Module ‘X’ can only be default-imported using the ‘esModuleInterop’ flag
CJSをESM風に書きたい時の代表エラー。tsconfigで一発解決します。
25-1. esModuleInterop の有効化
Before:
// ❌ TS1259発生する設定
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext"
}
}
After:
// ✅ esModuleInterop と allowSyntheticDefaultImports を有効に
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}
26. TS6133 unused variable(再掲・実務パターン)
分割代入での未使用変数は別の書き方で潰せます。
26-1. 分割代入で先頭だけ欲しい
Before:
// ❌ TS6133: 'b' is declared but its value is never read.
const [a, b] = [1, 2];
console.log(a);
After:
// ✅ アンダースコアで未使用宣言
const [a, _b] = [1, 2];
console.log(a);
// もしくは添字アクセス
const arr = [1, 2];
console.log(arr[0]);
27. TS2802 Type ‘X’ can only be iterated through when using the ‘–downlevelIteration’ flag
古いtarget(ES5など)で Map/Set/Iteratorをfor-ofで回した時のエラー。
27-1. tsconfigを近代化する
Before:
// ❌ TS2802 を誘発する古い設定
{
"compilerOptions": {
"target": "ES5",
"module": "CommonJS"
}
}
After:
// ✅ ES2022 / downlevelIteration は実質不要に
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"]
}
}
27-2. どうしてもES5が必要な場合
Before:
const map = new Map<string, number>([["a", 1]]);
// ❌ TS2802 (target: ES5)
for (const [k, v] of map) console.log(k, v);
After:
// ✅ downlevelIteration を有効に
{
"compilerOptions": {
"target": "ES5",
"downlevelIteration": true
}
}
28. TS5023 Unknown compiler option ‘X’
tsconfigのキーが古い/誤字/typescriptのバージョン非対応。意外と多い。
28-1. オプション名タイポ
Before:
{
"compilerOptions": {
// ❌ TS5023: Unknown compiler option 'strictNull'.
"strictNull": true
}
}
After:
{
"compilerOptions": {
// ✅ 正しいのは strictNullChecks(または strict)
"strict": true
}
}
28-2. TypeScriptのバージョン不足
Before:
# ❌ TS5023: Unknown compiler option 'verbatimModuleSyntax'.(TS4.4 で4.7+専用機能)
tsc --version
# Version 4.4.x
After:
# ✅ TypeScriptを5.x系へ更新
npm i -D -E typescript@latest
tsc --version
# Version 5.6.x
29. TS1192 Module ‘X’ has no default export
TS2305と双子のようなエラー。デフォルトエクスポートがないモジュールにdefaultで入った時に出る。
29-1. 名前付きimportに変える
Before:
// ❌ TS1192: Module '"./utils"' has no default export.
import utils from "./utils";
// utils.ts:
// export function add(a: number, b: number) { return a + b; }
After:
// ✅ 名前付きで取り出す
import { add } from "./utils";
add(1, 2);
// もしくは namespace import
import * as utils from "./utils";
utils.add(1, 2);
30. TS2304 Cannot find name(環境変数)
process.env や Vite の import.meta.env で出る典型エラー。
30-1. Node.jsの process
Before:
// ❌ TS2304: Cannot find name 'process'.
const port = process.env.PORT;
After:
# ✅ @types/node を入れる
npm i -D @types/node
// tsconfig.json
{
"compilerOptions": {
"types": ["node"]
}
}
30-2. Viteの import.meta.env を型安全に
Before:
// ❌ TS2339: Property 'VITE_API_URL' does not exist on type 'ImportMetaEnv'.
const url = import.meta.env.VITE_API_URL;
After(src/env.d.ts):
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string;
readonly VITE_GA_ID: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
// ✅ 補完が効くようになる
const url: string = import.meta.env.VITE_API_URL;
31. TS2589 Type instantiation is excessively deep and possibly infinite
再帰的なConditional Types や Mapped Types で爆発した時のエラー。深い型変換のライブラリで頻発します。
31-1. 再帰の打ち切り
Before:
// ❌ TS2589: 再帰深度制限に到達
type Repeat<S extends string, N extends number, Acc extends string = ""> =
Acc["length"] extends N ? Acc : Repeat<S, N, `${Acc}${S}`>;
type X = Repeat<"a", 1000>;
After:
// ✅ 深さを抑え、現実的な範囲に限定
type Repeat<S extends string, N extends number, Acc extends readonly unknown[] = []> =
Acc["length"] extends N ? Acc[number] extends never ? "" : string : Repeat<S, N, [...Acc, S]>;
// 100以上は実用上ほぼ不要。型のためだけに深い再帰を組まない
type Y = Repeat<"a", 8>;
32. tsconfig関連エラー総まとめ
tsconfigの最新ベストプラクティスをまとめておきます。これを土台にすればエラーの大半は予防可能です。
32-1. Web(Vite/React)向け推奨設定
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"resolveJsonModule": true,
"baseUrl": ".",
"paths": { "@/*": ["src/*"] }
},
"include": ["src"]
}
32-2. Node(サーバー)向け推奨設定
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"noUncheckedIndexedAccess": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "dist",
"rootDir": "src",
"types": ["node"]
},
"include": ["src"]
}
33. moduleResolution: bundler 移行時のエラー対処
Vite/Next.js/モダンバンドラ環境では moduleResolution: "bundler" が推奨ですが、旧コードからの移行でエラーが出ることがあります。
33-1. 拡張子付きimport要求エラー
Before:
// node モジュールでは動くが bundler モードでエラーになることがある
import { sum } from "./math"; // 拡張子なし
After:
// ✅ bundler モードに切り替える(拡張子未指定OK)
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"allowImportingTsExtensions": false
}
}
33-2. .ts拡張子つきimport(bundler 限定)
Before:
// ❌ NodeNextでは禁止される .ts 直接import
import { sum } from "./math.ts";
After:
// ✅ bundler モードかつ allowImportingTsExtensions: true で許可
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"noEmit": true
}
}
34. 補助: ESLint/TypeScript Eslint 連携エラー
TS本体エラーではないが、CIで一緒に落ちる定番の組み合わせ。
34-1. @typescript-eslint パーサ未設定
Before:
// .eslintrc.cjs
module.exports = {
// ❌ TS構文がパースできない
extends: ["eslint:recommended"],
};
After:
// .eslintrc.cjs
module.exports = {
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
],
parserOptions: {
project: "./tsconfig.json",
tsconfigRootDir: __dirname,
},
};
エラーをそもそも減らすための7つの設計指針
個別エラーを潰し続けるだけでなく、再発を抑える設計面の工夫も重要です。
- strictは最初から全部ON。後から有効化するとリファクタが地獄になる。
- any禁止、unknownで受ける。catch・JSON・外部APIはunknownから絞り込む。
- 判別可能ユニオンで型を分岐。
{ ok: true; data } | { ok: false; error }パターンを徹底。 - Zod等のスキーマライブラリで「型と実行時を一致」させる。
- satisfies演算子で「型に合致しつつ実態の精度を保つ」を活用。
- noUncheckedIndexedAccessを有効に。配列・Recordのundefined見落としを防止。
- tsconfigの定期点検。半年に1回はテンプレを最新化する。
satisfies の実用パターン
多くのエラーは satisfies で予防的に検知できます。
// 型は合っているか? を確認しつつ、実態の文字列リテラル型を温存する
type Status = "idle" | "loading" | "success" | "error";
// const assertion + satisfies で「ユニオンに属するか」+「リテラル温存」両立
const initial = "idle" as const satisfies Status;
// 型は "idle"(リテラル)、しかも Status の一員であることが保証される
// ルートマップで使うと便利
const routes = {
home: "/",
posts: "/posts",
about: "/about",
} as const satisfies Record<string, `/${string}`>;
type Route = (typeof routes)[keyof typeof routes];
// "/" | "/posts" | "/about"
1日でエラー耐性を底上げする学習ルート
ここまで30+パターン見てきましたが、エラーメッセージを「読める」状態にするには、独学だけでなく体系学習も有効です。型システムの背景・実務でのアンチパターン・現場でのレビュー文化まで含めて学べる選択肢を挙げておきます。
- テックアカデミー: TypeScript+Reactをマンツーマンメンタリングで詰められる。エラー解決の壁打ち相手として最適。
- 侍エンジニア: 現役エンジニア講師の個別カリキュラム。実務想定のコードレビュー量が多い。
- DMM WEBCAMP: チーム開発でのレビュー経験を積みたい人向け。Git運用も学べる。
- レバテックキャリア: TypeScript案件専門のキャリア相談。スクール卒業後の実戦の場としても有効。
よくある質問(FAQ)
Q1. anyを使えばエラーは消えますが、本当にダメですか?
短期的には消えますが、後で必ず実行時バグになって返ってきます。一時しのぎなら // @ts-expect-error 理由を書く の方が安全です(理由のコメントが必須化されるため)。
Q2. 非nullアサーション(!)はどこまで許容できますか?
「絶対にnullにならないと自分で証明できる場所」だけにとどめましょう。useRefの初期化直後、document.querySelectorでセレクタが固定の場合などです。配列要素アクセスやAPIレスポンスでは絶対に使ってはいけません。
Q3. エラーが多すぎて手をつけられない既存プロジェクト、どう移行しますか?
順番は (1) skipLibCheck: true でnode_modules関連を無効化、(2) strict: false で起動、(3) ファイル単位で // @ts-check を付けて部分strict化、(4) 段階的に noImplicitAny → strictNullChecks → strict の順に有効化、です。
Q4. TS2589 が出たら型を諦めるしかありませんか?
多くは型再帰の打ち切り条件を入れれば収まります。それでも収まらない場合は、型ではなく実行時(関数・パラメータ)で表現する方が現実的です。型は読めなくなった瞬間に負債になります。
Q5. verbatimModuleSyntax は有効にすべき?
新規プロジェクトでは 有効推奨。import type の徹底でバンドルサイズに優しく、二重import問題も防げます。
まとめ
TypeScriptのエラーは「言語が口うるさい」のではなく、本番で死ぬ前にコンパイラが代わりに死んでくれているとも言えます。本記事の30+パターンをBefore/Afterで身体に染み込ませれば、エラー解決速度は劇的に上がります。
大事なのは以下の3点です。
- エラーコードを読む癖をつける(TS+4桁を必ず控えてからググる)
- 絞り込みで解決する(
!/asは最終手段) - tsconfigを最新ベストプラクティスに保つ(半年に1度の点検を)
この記事をブックマークしておき、エラーに遭遇したらCtrl+Fでコード番号を検索する使い方をおすすめします。最強の自分専用リファレンスとしてどうぞ。

コメント