TypeScriptで開発していると、TS2554というエラーに遭遇することがあります。これは関数の呼び出し時に渡した引数の数が、関数定義のパラメータの数と一致しないときに発生するエラーです。
エラーメッセージは以下のような形式で表示されます。
Expected 2 arguments, but got 1. (TS2554)
日本語に訳すと「2つの引数が必要ですが、1つしか渡されていません」という意味です。JavaScriptでは引数の数が合わなくてもエラーにはなりませんが、TypeScriptではコンパイル時に引数の数を厳密にチェックします。そのため、引数の過不足があるとこのエラーが発生します。
この記事では、TS2554エラーが発生するすべてのパターンを網羅的に解説し、それぞれの原因と正しい解決方法をコード付きで紹介します。
この記事で学べること
- TS2554エラーの正確な意味とエラーメッセージの読み方
- 引数が多すぎる・少なすぎる場合の基本的な解決方法
- オプショナル引数(?)とデフォルト引数での TS2554 対策
- rest パラメータ(…args)とスプレッド演算子での可変長引数
- 関数オーバーロードで引数の数を柔軟に受け取る方法
- コールバック関数(map / filter / reduce / addEventListener 等)での TS2554
- クラス・コンストラクタ・super() での TS2554 パターン
- React Hooks・コンポーネント Props での TS2554 パターン
- 外部ライブラリのバージョンアップ時の引数変更への対処
- 実務でよくある TS2554 パターン10選と解決アプローチ
TS2554エラーとは?
エラーメッセージの読み方
TS2554のエラーメッセージは次の形式で出力されます。
Expected N arguments, but got M. (TS2554)
このメッセージを分解すると以下のようになります。
| パーツ |
意味 |
Expected N arguments |
関数が期待する引数の数(N個) |
but got M |
実際に渡された引数の数(M個) |
(TS2554) |
TypeScriptのエラーコード |
つまり、「関数定義ではN個の引数が必要ですが、呼び出し時にM個しか(またはM個も)渡されています」ということを伝えています。Nが期待値、Mが実際の値であり、N ≠ M のときにエラーが発生します。
JavaScriptとTypeScriptの引数チェックの違い
JavaScriptでは引数の数が合わなくてもエラーにはなりません。不足している引数は undefined になり、余分な引数は単に無視されます。
JavaScript:引数の数が合わなくてもエラーにならない
// JavaScriptの場合
function greet(name, greeting) {
return greeting + ", " + name;
}
// 引数が足りなくても実行される(greeting は undefined)
console.log(greet("太郎")); // "undefined, 太郎"
// 引数が多くても実行される(余分な引数は無視)
console.log(greet("太郎", "こんにちは", "余分")); // "こんにちは, 太郎"
一方、TypeScriptでは引数の数をコンパイル時にチェックするため、数が合わないとTS2554エラーになります。
TypeScript:引数の数が合わないとコンパイルエラー
function greet(name: string, greeting: string): string {
return greeting + ", " + name;
}
// TS2554: Expected 2 arguments, but got 1.
greet("太郎");
// TS2554: Expected 2 arguments, but got 3.
greet("太郎", "こんにちは", "余分");
JavaScriptとTypeScriptの引数チェックの違い
- JavaScript:引数の数が合わなくても実行時エラーにならない(不足は
undefined、余分は無視)
- TypeScript:コンパイル時に引数の数を厳密にチェックし、一致しなければ TS2554 エラーを出す
- この仕組みにより、引数の渡し忘れや余分な引数によるバグを実行前に検出できる
TS2554が発生する代表的なパターン
TS2554エラーは主に以下のパターンで発生します。
| パターン |
例 |
エラーメッセージ |
| 引数が多すぎる |
fn(a, b, c) ← 2引数の関数 |
Expected 2 arguments, but got 3 |
| 引数が少なすぎる |
fn(a) ← 2引数の関数 |
Expected 2 arguments, but got 1 |
| 0引数に引数を渡す |
fn(a) ← 0引数の関数 |
Expected 0 arguments, but got 1 |
| コンストラクタの引数不一致 |
new MyClass() ← 引数が必要 |
Expected 1 arguments, but got 0 |
| super() の引数不一致 |
super() ← 親クラスが引数を要求 |
Expected 1 arguments, but got 0 |
| ライブラリ更新後の引数変更 |
API の引数仕様が変わった |
Expected N arguments, but got M |
それでは、各パターンを詳しく見ていきましょう。
基本的なケースと解決方法
引数が多すぎる場合
関数定義で宣言されているパラメータの数よりも多くの引数を渡すと、TS2554が発生します。
Expected 2 arguments, but got 3. (TS2554)
エラーが出るコード
function add(a: number, b: number): number {
return a + b;
}
// TS2554: Expected 2 arguments, but got 3.
const result = add(1, 2, 3);
原因:add 関数は a と b の2つのパラメータしか定義していないのに、3つの引数を渡しています。
解決方法1:余分な引数を削除する。
解決方法1:余分な引数を削除
const result = add(1, 2); // OK: 3
解決方法2:3つの引数を受け取れるように関数を修正する。
解決方法2:パラメータを追加
function add(a: number, b: number, c: number): number {
return a + b + c;
}
const result = add(1, 2, 3); // OK: 6
解決方法3:可変長引数にする場合は rest パラメータを使う。
解決方法3:rest パラメータで可変長引数に対応
function add(...nums: number[]): number {
return nums.reduce((sum, n) => sum + n, 0);
}
const result = add(1, 2, 3); // OK: 6
const result2 = add(1, 2, 3, 4, 5); // OK: 15
引数が少なすぎる場合
必須パラメータが定義されているのに、引数を省略して呼び出すとTS2554が発生します。
Expected 2 arguments, but got 1. (TS2554)
エラーが出るコード
function createUser(name: string, age: number): void {
console.log(`${name}さん(${age}歳)を作成しました`);
}
// TS2554: Expected 2 arguments, but got 1.
createUser("太郎");
原因:createUser 関数は name と age の2つの引数が必須ですが、name しか渡していません。
解決方法1:不足している引数を追加する。
解決方法1:不足している引数を追加
createUser("太郎", 25); // OK
解決方法2:省略可能にしたい引数をオプショナルにする。
解決方法2:オプショナル引数にする
function createUser(name: string, age?: number): void {
if (age !== undefined) {
console.log(`${name}さん(${age}歳)を作成しました`);
} else {
console.log(`${name}さんを作成しました`);
}
}
createUser("太郎"); // OK: "太郎さんを作成しました"
createUser("太郎", 25); // OK: "太郎さん(25歳)を作成しました"
解決方法3:デフォルト引数を使う。
解決方法3:デフォルト引数を使う
function createUser(name: string, age: number = 0): void {
console.log(`${name}さん(${age}歳)を作成しました`);
}
createUser("太郎"); // OK: "太郎さん(0歳)を作成しました"
createUser("太郎", 25); // OK: "太郎さん(25歳)を作成しました"
0引数の関数に引数を渡した場合
パラメータを一切取らない関数に引数を渡すとTS2554が発生します。
Expected 0 arguments, but got 1. (TS2554)
エラーが出るコード
function getTimestamp(): number {
return Date.now();
}
// TS2554: Expected 0 arguments, but got 1.
const ts = getTimestamp("now");
原因:getTimestamp 関数はパラメータを一切受け取らないのに、"now" という引数を渡しています。
解決方法:余分な引数を削除する。
解決方法
const ts = getTimestamp(); // OK
引数の数を間違えやすいケース
以下は引数の数を間違えやすい典型的なパターンです。
Math メソッドの引数数
Math メソッドの引数間違い
// Math.max は rest パラメータなので何個でも OK
Math.max(1, 2, 3); // OK
// Math.pow は2引数固定
// TS2554: Expected 2 arguments, but got 3.
Math.pow(2, 3, 4);
// 正しくは
Math.pow(2, 3); // OK: 8
String メソッドの引数数
String メソッドの引数間違い
const str = "Hello World";
// startsWith は1〜2引数(第2引数はオプショナル)
str.startsWith("Hello"); // OK
str.startsWith("World", 6); // OK
// TS2554: Expected 1-2 arguments, but got 3.
str.startsWith("Hello", 0, 5);
アロー関数の引数間違い
アロー関数の引数間違い
const multiply = (a: number, b: number): number => a * b;
// TS2554: Expected 2 arguments, but got 1.
multiply(5);
// TS2554: Expected 2 arguments, but got 3.
multiply(2, 3, 4);
// 正しくは
multiply(2, 3); // OK: 6
オプショナル引数でのTS2554
TypeScriptでは、引数名の後ろに ? を付けることで、その引数を省略可能(オプショナル)にできます。オプショナル引数を正しく使うことで、TS2554エラーを防ぐことができます。
?(オプショナルパラメータ)の基本
オプショナルパラメータは、渡しても渡さなくてもよい引数です。省略した場合、値は undefined になります。
オプショナルパラメータの基本
function greet(name: string, greeting?: string): string {
if (greeting) {
return `${greeting}, ${name}!`;
}
return `こんにちは, ${name}!`;
}
// どちらも OK
greet("太郎"); // "こんにちは, 太郎!"
greet("太郎", "おはよう"); // "おはよう, 太郎!"
オプショナルパラメータを使うことで、greet("太郎") のように1引数で呼び出してもTS2554は発生しません。
オプショナル引数を使わないとTS2554になるケース
オプショナルにすべき引数を必須のまま残していると、引数を省略した時にTS2554が発生します。
Expected 3 arguments, but got 1. (TS2554)
エラーが出るコード
function sendEmail(to: string, subject: string, body: string): void {
console.log(`To: ${to}, Subject: ${subject}, Body: ${body}`);
}
// TS2554: Expected 3 arguments, but got 1.
sendEmail("user@example.com");
解決方法:省略可能な引数に ? を付ける。
解決方法:オプショナルパラメータにする
function sendEmail(to: string, subject?: string, body?: string): void {
const subj = subject ?? "(件名なし)";
const b = body ?? "";
console.log(`To: ${to}, Subject: ${subj}, Body: ${b}`);
}
sendEmail("user@example.com"); // OK
sendEmail("user@example.com", "お知らせ"); // OK
sendEmail("user@example.com", "お知らせ", "本文です"); // OK
デフォルト引数との違い
デフォルト引数とオプショナル引数は似ていますが、動作が異なります。
| 特徴 |
オプショナル引数(?) |
デフォルト引数(= value) |
| 省略時の値 |
undefined |
指定したデフォルト値 |
| 型 |
T | undefined |
T(undefined チェック不要) |
| undefined を明示的に渡す |
undefined のまま |
デフォルト値が使われる |
| 省略可能? |
はい |
はい |
オプショナル引数 vs デフォルト引数
// オプショナル引数:省略時は undefined
function greetOptional(name: string, prefix?: string): string {
// prefix は string | undefined 型
return `${prefix ?? "さん"}:${name}`;
}
// デフォルト引数:省略時はデフォルト値
function greetDefault(name: string, prefix: string = "さん"): string {
// prefix は string 型(undefined チェック不要)
return `${prefix}:${name}`;
}
greetOptional("太郎"); // "さん:太郎"
greetOptional("太郎", undefined); // "さん:太郎"
greetDefault("太郎"); // "さん:太郎"
greetDefault("太郎", undefined); // "さん:太郎" (デフォルト値が適用される)
ポイント:省略時に undefined のまま使いたい場合はオプショナル引数(?)、デフォルト値を設定したい場合はデフォルト引数(= value)を使いましょう。デフォルト引数の方が関数内で undefined チェックが不要になるため、コードがシンプルになります。
オプショナル引数の位置のルール
TypeScriptでは、オプショナル引数は必須引数の後ろに配置する必要があります。必須引数の前にオプショナル引数を置くとエラーになります。
オプショナル引数の位置ルール
// エラー:オプショナル引数が必須引数の前にある
// A required parameter cannot follow an optional parameter. (TS1016)
function badOrder(a?: string, b: number): void {}
// OK:必須引数が先、オプショナル引数が後
function goodOrder(a: string, b?: number): void {}
注意:このルールは TS2554 ではなく TS1016 エラーですが、オプショナル引数の順序を間違えると、結果的に引数の渡し方が複雑になり TS2554 を引き起こす原因にもなります。
複数のオプショナル引数
複数のオプショナル引数がある場合、途中の引数だけをスキップすることはできません。
途中のオプショナル引数をスキップする問題
function configure(host: string, port?: number, ssl?: boolean): void {
console.log(`${ssl ? "https" : "http"}://${host}:${port ?? 80}`);
}
// port をスキップして ssl だけ渡したい場合…
// これは意図通りに動かない(true が port に渡される)
// TS2345: Argument of type 'boolean' is not assignable to parameter of type 'number'.
configure("localhost", true);
// 正しくは、undefined を明示的に渡してスキップする
configure("localhost", undefined, true); // OK
途中の引数をスキップする必要がある場合は、オブジェクト引数パターン(Options パターン)を使うとスマートに解決できます。
Options パターンで解決
interface ConfigOptions {
host: string;
port?: number;
ssl?: boolean;
}
function configure(options: ConfigOptions): void {
const { host, port = 80, ssl = false } = options;
console.log(`${ssl ? "https" : "http"}://${host}:${port}`);
}
// 必要なプロパティだけ指定すればOK
configure({ host: "localhost", ssl: true }); // OK: "https://localhost:80"
configure({ host: "localhost", port: 3000 }); // OK: "http://localhost:3000"
ポイント:オプショナル引数が3つ以上ある場合や、途中の引数をスキップしたい場合は、Options パターン(オブジェクト引数)を使うことをおすすめします。これにより TS2554 が発生する可能性を大幅に減らせます。
rest パラメータでのTS2554
TypeScriptの rest パラメータ(...args)を使うと、可変長の引数を受け取る関数を定義できます。rest パラメータを正しく理解することで、TS2554エラーを柔軟に解決できます。
rest パラメータの基本
rest パラメータは、パラメータ名の前に ... を付けることで定義します。渡された引数はすべて配列として受け取ります。
rest パラメータの基本
// 可変長の数値引数を受け取る
function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}
// 何個でも引数を渡せる
sum(1); // OK: 1
sum(1, 2); // OK: 3
sum(1, 2, 3, 4, 5); // OK: 15
sum(); // OK: 0(空配列)
rest パラメータで可変長引数を受け取る
固定引数が足りない場合に TS2554 が発生していたら、rest パラメータに切り替えることで解決できることがあります。
Expected 3 arguments, but got 5. (TS2554)
エラーが出るコード
function log(level: string, msg1: string, msg2: string): void {
console.log(`[${level}] ${msg1} ${msg2}`);
}
// TS2554: Expected 3 arguments, but got 5.
log("INFO", "User", "logged", "in", "successfully");
解決方法:rest パラメータを使って可変長にする。
解決方法:rest パラメータを使う
function log(level: string, ...messages: string[]): void {
console.log(`[${level}] ${messages.join(" ")}`);
}
// 何個でもメッセージを渡せる
log("INFO", "User", "logged", "in", "successfully");
// [INFO] User logged in successfully
log("ERROR", "Connection failed");
// [ERROR] Connection failed
注意:rest パラメータは必ず最後のパラメータに配置する必要があります。function fn(...args: string[], last: number) のような定義はできません。
タプル型の rest パラメータ
TypeScript 3.0以降では、rest パラメータにタプル型を使用できます。これにより、可変長でありながら各引数の型を個別に指定できます。
タプル型の rest パラメータ
// タプル型で引数の型と数を厳密に指定
function createRecord(...args: [string, number, boolean]): void {
const [name, age, active] = args;
console.log(`${name}, ${age}, ${active}`);
}
createRecord("太郎", 25, true); // OK
// TS2554: Expected 3 arguments, but got 2.
createRecord("太郎", 25);
// TS2554: Expected 3 arguments, but got 4.
createRecord("太郎", 25, true, "extra");
タプル型にオプショナル要素を含めることもできます。
オプショナル要素を持つタプル
function query(...args: [string, number?, boolean?]): void {
const [sql, limit, debug] = args;
console.log(sql, limit ?? 100, debug ?? false);
}
query("SELECT * FROM users"); // OK
query("SELECT * FROM users", 50); // OK
query("SELECT * FROM users", 50, true); // OK
スプレッド演算子で配列を展開して渡す
配列をスプレッド演算子(...)で展開して関数に渡す場合、TypeScriptは配列の長さを型レベルで判定します。可変長配列を固定引数の関数に渡すと TS2556 が発生することがありますが、as const アサーションやタプル型を使って解決できます。
A spread argument must either have a tuple type or be passed to a rest parameter. (TS2556)
スプレッドで配列を渡す際のエラー
function add(a: number, b: number): number {
return a + b;
}
const nums = [1, 2]; // number[] と推論される
// TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
add(...nums);
原因:nums は number[](可変長配列)と推論されるため、TypeScriptは要素数が2であることを保証できません。
解決方法1:as const でタプル型にする。
解決方法1:as const
const nums = [1, 2] as const; // readonly [1, 2] と推論される
add(...nums); // OK: 3
解決方法2:タプル型で変数を宣言する。
解決方法2:タプル型で宣言
const nums: [number, number] = [1, 2];
add(...nums); // OK: 3
解決方法3:関数側を rest パラメータにする。
解決方法3:関数を rest パラメータにする
function add(...nums: number[]): number {
return nums.reduce((a, b) => a + b, 0);
}
const nums = [1, 2];
add(...nums); // OK: 3
rest パラメータと固定パラメータの組み合わせ
rest パラメータは固定パラメータと組み合わせて使えます。固定パラメータが先、rest パラメータが最後です。
固定パラメータ + rest パラメータ
function format(template: string, ...values: (string | number)[]): string {
return template.replace(/{(\d+)}/g, (_, i) =>
String(values[Number(i)])
);
}
// template は必須、残りは可変長
format("{0}さんは{1}歳です", "太郎", 25);
// "太郎さんは25歳です"
// TS2554: Expected 1 arguments, but got 0.
// template は必須なので省略するとエラー
format();
rest パラメータまとめ
...args: T[] で可変長引数を受け取れる
- rest パラメータは必ず最後のパラメータに配置する
- タプル型の rest パラメータで引数の数と型を厳密に指定できる
- 配列をスプレッドで渡す場合は
as const またはタプル型を使う
- 固定パラメータ + rest パラメータの組み合わせが可能
オーバーロードでのTS2554
TypeScriptの関数オーバーロードを使うと、同じ関数名で異なる引数パターンを受け取れます。しかし、オーバーロードの定義が正しくないと TS2554 エラーが発生します。
関数オーバーロードの基本
関数オーバーロードは、複数のオーバーロードシグネチャと1つの実装シグネチャで構成されます。
関数オーバーロードの基本構造
// オーバーロードシグネチャ(呼び出し側から見える型定義)
function convert(value: string): number;
function convert(value: number): string;
// 実装シグネチャ(実際の処理)
function convert(value: string | number): string | number {
if (typeof value === "string") {
return Number(value);
}
return String(value);
}
convert("123"); // OK: 123 (number)
convert(456); // OK: "456" (string)
オーバーロードシグネチャと引数の数
オーバーロードで異なる引数の数を定義できます。呼び出し時はオーバーロードシグネチャのいずれかにマッチする必要があります。
Expected 1-2 arguments, but got 3. (TS2554)
オーバーロードでの引数数エラー
// 1引数または2引数のオーバーロード
function createDate(timestamp: number): Date;
function createDate(year: number, month: number): Date;
function createDate(yearOrTimestamp: number, month?: number): Date {
if (month !== undefined) {
return new Date(yearOrTimestamp, month - 1);
}
return new Date(yearOrTimestamp);
}
createDate(1700000000000); // OK
createDate(2024, 3); // OK
// TS2554: Expected 1-2 arguments, but got 3.
createDate(2024, 3, 15);
解決方法:3引数のオーバーロードシグネチャを追加する。
解決方法:3引数のオーバーロードを追加
function createDate(timestamp: number): Date;
function createDate(year: number, month: number): Date;
function createDate(year: number, month: number, day: number): Date;
function createDate(a: number, b?: number, c?: number): Date {
if (b !== undefined && c !== undefined) {
return new Date(a, b - 1, c);
}
if (b !== undefined) {
return new Date(a, b - 1);
}
return new Date(a);
}
createDate(2024, 3, 15); // OK
実装シグネチャとの関係
呼び出し側から見えるのはオーバーロードシグネチャだけです。実装シグネチャは呼び出しに使えません。これがTS2554の原因になることがあります。
実装シグネチャは呼び出しに使えない
function process(value: string): string;
function process(value: number): number;
// 実装シグネチャ(3引数を受け取れるが、呼び出しには使えない)
function process(value: string | number, extra?: boolean, debug?: boolean): string | number {
return value;
}
// オーバーロードシグネチャはどちらも1引数なので...
// TS2554: Expected 1 arguments, but got 2.
process("hello", true);
解決方法:呼び出しに使いたい引数パターンはすべてオーバーロードシグネチャに定義する必要があります。
解決方法
function process(value: string): string;
function process(value: number): number;
function process(value: string, extra: boolean): string;
function process(value: string | number, extra?: boolean): string | number {
return value;
}
process("hello", true); // OK
オーバーロード vs ユニオン型パラメータ
引数の数が異なる場合はオーバーロードが必要ですが、引数の型だけが異なる場合はユニオン型で代用できることが多いです。
| 使い分け |
方法 |
例 |
| 引数の数が異なる |
オーバーロード |
fn(a) or fn(a, b) |
| 引数の型だけ異なる |
ユニオン型 |
fn(a: string | number) |
| 戻り値が引数型に依存 |
オーバーロード or ジェネリクス |
fn(s: string): number |
ユニオン型で十分なケース
// オーバーロードを使わなくてもよい(型だけ異なる)
function stringify(value: string | number | boolean): string {
return String(value);
}
stringify("hello"); // OK
stringify(42); // OK
stringify(true); // OK
ポイント:オーバーロードはコードが複雑になりやすいので、ユニオン型やオプショナル引数で解決できる場合はそちらを優先しましょう。オーバーロードが必要なのは「引数の数が異なり、かつ戻り値の型が引数パターンごとに異なる」場合です。
コールバック関数でのTS2554
コールバック関数を使う場面でもTS2554エラーは頻繁に発生します。特に、配列メソッドやイベントリスナー、Promise などでコールバックの引数の数が期待と合わない場合にエラーになります。
Array.map / filter / reduce のコールバック引数
配列メソッドのコールバックに渡す関数の引数が合わない場合、TS2554が発生することがあります。ただし、TypeScriptではコールバック関数の引数は少なくてもエラーにならない(余分なパラメータの省略は許容される)という特性があります。
コールバックの引数省略は OK
const numbers = [1, 2, 3];
// map のコールバックは (value, index, array) の3引数だが…
// 使わない引数は省略してOK
numbers.map((n) => n * 2); // OK: 1引数だけ使う
numbers.map((n, i) => n + i); // OK: 2引数使う
numbers.map((n, i, arr) => n + i); // OK: 3引数すべて使う
しかし、コールバックに定義済みの関数を渡す場合、その関数の引数パターンが期待と一致しないとエラーになることがあります。
Expected 1 arguments, but got 3. (TS2554)
コールバック関数の引数不一致
// カスタムのコールバック型を定義
type Callback = (value: number) => void;
function execute(cb: Callback): void {
cb(42);
}
// この関数は2引数を要求する
function handler(value: number, label: string): void {
console.log(label, value);
}
// Callback型は1引数しか渡さないので、handler(2引数)と互換性がない場合がある
// ただし、TypeScriptでは引数が少ないコールバックは互換性があるとみなされる
// (逆に引数が多いコールバックは互換性がない場合がある)
execute(handler); // strictFunctionTypes が有効だとエラーになる場合がある
addEventListener のコールバック
DOM の addEventListener でコールバック関数を渡す際、イベントオブジェクトの型が合わないとエラーが発生することがあります。
addEventListener でのコールバック
// addEventListener は2〜3引数
const button = document.getElementById("btn");
// OK: 2引数(イベント名, コールバック)
button?.addEventListener("click", (e) => {
console.log(e.target);
});
// OK: 3引数(イベント名, コールバック, オプション)
button?.addEventListener("click", (e) => {
console.log(e.target);
}, { once: true });
// TS2554: Expected 2-3 arguments, but got 1.
button?.addEventListener("click");
Promise の then / catch
Promise の then や catch に渡すコールバックは、通常1引数(resolved value または error)です。
Promise のコールバック
const promise = new Promise<string>((resolve) => {
resolve("成功");
});
// OK: then に1引数のコールバック
promise.then((result) => console.log(result));
// OK: then に2引数(onFulfilled, onRejected)
promise.then(
(result) => console.log(result),
(error) => console.error(error)
);
// Promise コンストラクタの executor は resolve と reject の2引数
// TS2554: Expected 1-2 arguments, but got 0. (resolve を呼び忘れたケース)
const p = new Promise<string>((resolve) => {
// resolve() を呼ばずに return してしまう
// resolve に引数を渡し忘れ
resolve(); // TS2554: Expected 1 arguments, but got 0.
});
解決方法:resolve に正しい型の値を渡す。
解決方法
// Promise<string> なので resolve に string を渡す
const p = new Promise<string>((resolve) => {
resolve("成功"); // OK
});
// 引数なしの resolve にしたい場合は Promise<void>
const p2 = new Promise<void>((resolve) => {
resolve(); // OK
});
setTimeout / setInterval
setTimeout と setInterval は最低2引数(コールバックと遅延時間)が必要です。
setTimeout / setInterval
// OK: 標準的な使い方
setTimeout(() => {
console.log("1秒後");
}, 1000);
// OK: 遅延時間を省略(0ms として扱われる)
setTimeout(() => {
console.log("すぐ実行");
});
// setTimeout に追加の引数を渡すこともできる(コールバックの引数になる)
setTimeout((msg: string) => {
console.log(msg);
}, 1000, "Hello"); // OK: "Hello" がコールバックの msg に渡される
カスタムコールバック型の定義
自分でコールバック型を定義する際は、引数の数と型を慎重に設計しましょう。呼び出す側と渡す側の引数数が一致しないと TS2554 が発生します。
Expected 2 arguments, but got 1. (TS2554)
カスタムコールバック型でのエラー
type EventHandler = (event: string, data: unknown) => void;
function on(eventName: string, handler: EventHandler): void {
// イベント発火時にコールバックを呼ぶ
handler(eventName, { timestamp: Date.now() });
}
// コールバックで event だけ使い、data を無視するのは OK
on("click", (event) => {
console.log(event); // OK: 引数が少ないのは許容される
});
// しかし、handler を呼び出す側が引数を足りなく渡すとエラー
function onBroken(eventName: string, handler: EventHandler): void {
// TS2554: Expected 2 arguments, but got 1.
handler(eventName); // data が足りない
}
解決方法:呼び出す側がコールバックの引数を正しく渡す、またはコールバック型の引数をオプショナルにする。
解決方法
// 方法1:コールバック呼び出し時に引数を正しく渡す
function onFixed(eventName: string, handler: EventHandler): void {
handler(eventName, { timestamp: Date.now() }); // OK
}
// 方法2:コールバック型の引数をオプショナルにする
type EventHandlerOptional = (event: string, data?: unknown) => void;
コールバック関数の引数ルールまとめ
- コールバックの引数は少なく定義してもOK(余分な引数は無視される)
- コールバックを呼び出す側は、定義された引数をすべて渡す必要がある
- Promise<T> の resolve には T 型の値を渡す必要がある(void 以外)
- addEventListener は2〜3引数で、コールバック省略はできない
クラス・コンストラクタでのTS2554
クラスのコンストラクタやsuper()呼び出しでも、引数の数が合わないとTS2554が発生します。クラスを使ったオブジェクト指向プログラミングでよく遭遇するパターンを見ていきましょう。
コンストラクタの引数不足
クラスのコンストラクタに定義された必須パラメータを省略するとTS2554が発生します。
Expected 2 arguments, but got 0. (TS2554)
コンストラクタの引数不足
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
// TS2554: Expected 2 arguments, but got 0.
const user1 = new User();
// TS2554: Expected 2 arguments, but got 1.
const user2 = new User("太郎");
解決方法1:必要な引数をすべて渡す。
解決方法1:引数を正しく渡す
const user = new User("太郎", 25); // OK
解決方法2:一部の引数をオプショナルにする。
解決方法2:オプショナルコンストラクタ
class User {
name: string;
age: number;
constructor(name: string, age: number = 0) {
this.name = name;
this.age = age;
}
}
const user = new User("太郎"); // OK: age は 0
コンストラクタの引数過多
Expected 2 arguments, but got 3. (TS2554)
コンストラクタの引数過多
class Point {
constructor(public x: number, public y: number) {}
}
// TS2554: Expected 2 arguments, but got 3.
const p = new Point(1, 2, 3); // 3D座標を渡そうとしている
解決方法:3D座標が必要な場合は、z パラメータを追加するか、別のクラスを作成します。
解決方法
class Point3D {
constructor(
public x: number,
public y: number,
public z: number
) {}
}
const p = new Point3D(1, 2, 3); // OK
super() の引数
子クラスのコンストラクタで super() を呼ぶ際、親クラスのコンストラクタが期待する引数を正しく渡す必要があります。
Expected 2 arguments, but got 0. (TS2554)
super() の引数忘れ
class Animal {
constructor(public name: string, public age: number) {}
}
class Dog extends Animal {
breed: string;
constructor(breed: string) {
// TS2554: Expected 2 arguments, but got 0.
super(); // Animal のコンストラクタには name と age が必要
this.breed = breed;
}
}
解決方法:super() に親クラスのコンストラクタが期待する引数を渡す。
解決方法
class Dog extends Animal {
breed: string;
constructor(name: string, age: number, breed: string) {
super(name, age); // OK: 親クラスの引数を渡す
this.breed = breed;
}
}
const dog = new Dog("ポチ", 3, "柴犬"); // OK
new キーワードでのインスタンス化
コンストラクタのないクラスや、コンストラクタが引数を取らないクラスに引数を渡すとエラーになります。
引数なしコンストラクタ
class Logger {
// コンストラクタを明示的に定義していない = 0引数
log(message: string): void {
console.log(message);
}
}
// TS2554: Expected 0 arguments, but got 1.
const logger = new Logger("debug");
// 正しくは
const logger2 = new Logger(); // OK
ファクトリパターンでの引数管理
ファクトリ関数でインスタンスを生成する場合、ファクトリ関数の引数とコンストラクタの引数が一致している必要があります。
ファクトリパターン
class Product {
constructor(
public name: string,
public price: number,
public category: string
) {}
}
// ファクトリ関数でコンストラクタ引数を中継
function createProduct(
name: string,
price: number,
category: string = "一般"
): Product {
return new Product(name, price, category);
}
// ファクトリ関数は category にデフォルト値があるので2引数でもOK
createProduct("りんご", 300); // OK
createProduct("りんご", 300, "食品"); // OK
ポイント:コンストラクタの引数が多い場合は、Options パターン(オブジェクト引数)を使うとミスを減らせます。特に4つ以上の引数がある場合は、オブジェクトにまとめることを検討しましょう。
Options パターンのコンストラクタ
interface UserOptions {
name: string;
age: number;
email?: string;
role?: "admin" | "user";
}
class User {
name: string;
age: number;
email: string;
role: string;
constructor(options: UserOptions) {
this.name = options.name;
this.age = options.age;
this.email = options.email ?? "";
this.role = options.role ?? "user";
}
}
// 必要なプロパティだけ指定すればOK(引数は常に1つ)
const user = new User({ name: "太郎", age: 25 }); // OK
const admin = new User({ name: "管理者", age: 30, role: "admin" }); // OK
React / フレームワークでのTS2554
ReactをTypeScriptで使う場合、Hooks やコンポーネントの Props で TS2554 が発生することがあります。ここでは React 特有のパターンを見ていきます。
useState の引数
useState は0〜1引数を受け取ります。初期値を渡すかどうかでTS2554が発生するケースがあります。
useState の正しい使い方
import { useState } from "react";
// OK: 初期値あり(型は自動推論される)
const [count, setCount] = useState(0);
// OK: 初期値なし(型を明示的に指定)
const [name, setName] = useState<string>();
// OK: 初期値に関数を渡す(lazy initialization)
const [data, setData] = useState(() => computeInitial());
// TS2554: Expected 0-1 arguments, but got 2.
const [value, setValue] = useState(0, "extra");
useEffect の引数
useEffect は1〜2引数(エフェクト関数と依存配列)を受け取ります。
useEffect の引数
import { useEffect } from "react";
// OK: エフェクト関数のみ(毎回実行)
useEffect(() => {
console.log("レンダリングされました");
});
// OK: エフェクト関数 + 依存配列
useEffect(() => {
console.log(`count: ${count}`);
}, [count]);
// OK: 空の依存配列(マウント時のみ実行)
useEffect(() => {
console.log("マウントされました");
}, []);
// TS2554: Expected 1-2 arguments, but got 3.
useEffect(() => {}, [], "extra");
useCallback / useMemo の引数
useCallback と useMemo は2引数(関数と依存配列)が必須です。
Expected 2 arguments, but got 1. (TS2554)
useCallback の依存配列忘れ
import { useCallback, useMemo } from "react";
// TS2554: Expected 2 arguments, but got 1.
const handleClick = useCallback(() => {
console.log("clicked");
}); // 依存配列が足りない!
// TS2554: Expected 2 arguments, but got 1.
const expensive = useMemo(() => {
return heavyComputation();
}); // 依存配列が足りない!
解決方法:第2引数に依存配列を渡す。
解決方法:依存配列を渡す
const handleClick = useCallback(() => {
console.log("clicked");
}, []); // OK: 空の依存配列
const expensive = useMemo(() => {
return heavyComputation(count);
}, [count]); // OK: count が変わったら再計算
カスタムフックの引数
カスタムフックの引数が変更された場合、呼び出し側でTS2554が発生します。
カスタムフックの引数変更
// カスタムフック(初期は1引数だった)
function useFetch(url: string): { data: unknown; loading: boolean } {
// ...
return { data: null, loading: false };
}
// フック作者がオプションパラメータを追加(必須に変更してしまった)
function useFetchV2(url: string, options: RequestInit): { data: unknown; loading: boolean } {
// ...
return { data: null, loading: false };
}
// 既存の呼び出しが壊れる
// TS2554: Expected 2 arguments, but got 1.
const { data } = useFetchV2("/api/users");
解決方法:新しいパラメータはオプショナルにする。
解決方法:オプショナルにする
function useFetch(url: string, options?: RequestInit): { data: unknown; loading: boolean } {
// ...
return { data: null, loading: false };
}
const { data } = useFetch("/api/users"); // OK
const { data: d2 } = useFetch("/api/users", { method: "POST" }); // OK
コンポーネントの Props(関数コンポーネント)
React コンポーネントの Props は通常1つのオブジェクトとして渡されるため、TS2554は発生しにくいですが、コンポーネントを直接関数として呼び出す場合に発生することがあります。
コンポーネントを関数として呼ぶ場合
interface ButtonProps {
label: string;
onClick: () => void;
}
const Button = ({ label, onClick }: ButtonProps) => (
<button onClick={onClick}>{label}</button>
);
// JSX として使う場合はTS2554にはならない
// (Props は JSX 属性として渡される)
<Button label="クリック" onClick={() => {}} /> // OK
// 関数として直接呼ぶとTS2554の可能性
// TS2554: Expected 1 arguments, but got 0.
Button(); // Props なしで呼ぶとエラー
イベントハンドラの引数
React のイベントハンドラで引数の数が合わないケースです。
イベントハンドラの引数
import React from "react";
// ハンドラに追加の引数を渡したい場合
function handleDelete(id: number, event: React.MouseEvent): void {
event.preventDefault();
console.log(`Delete item ${id}`);
}
// onClick は (event) => void なので、handleDelete(id, event) を直接渡せない
// アロー関数でラップする
<button onClick={(e) => handleDelete(123, e)}>削除</button> // OK
React.createElement の引数
React.createElement は最低1引数(コンポーネントまたはタグ名)が必要です。通常はJSXを使うため直接使うことは少ないですが、知っておくと役立ちます。
React.createElement
// OK: タグ名のみ
React.createElement("div");
// OK: タグ名 + props
React.createElement("div", { className: "container" });
// OK: タグ名 + props + children
React.createElement("div", { className: "container" }, "Hello");
// TS2554: Expected 1 arguments, but got 0.
React.createElement(); // タグ名が必要
React での TS2554 まとめ
useCallback / useMemo は依存配列が必須(2引数)
useEffect は1〜2引数(依存配列はオプショナル)
useState は0〜1引数(初期値はオプショナル)
- カスタムフックの引数変更時は破壊的変更にならないようオプショナルにする
- イベントハンドラに追加引数を渡す場合はアロー関数でラップする
外部ライブラリでのTS2554
外部ライブラリを使用している際にTS2554が発生する場合、ライブラリのバージョンアップや型定義の不一致が原因であることが多いです。
ライブラリのバージョンアップで引数が変わった場合
ライブラリのメジャーアップデートでAPIの引数が変わると、既存のコードでTS2554が発生します。
ライブラリ更新後のTS2554例
// ライブラリの旧バージョン(v1)
// function connect(host: string, port: number): Connection;
// ライブラリの新バージョン(v2)- 引数がオブジェクトに変更された
// function connect(options: ConnectionOptions): Connection;
// v1 の呼び出しコードがそのまま残っている
// TS2554: Expected 1 arguments, but got 2.
connect("localhost", 3000);
// v2 の正しい呼び出し
connect({ host: "localhost", port: 3000 }); // OK
注意:ライブラリをアップデートした後にTS2554が大量に発生した場合は、まずライブラリのマイグレーションガイドやCHANGELOGを確認しましょう。APIの引数が変更されている可能性が高いです。
型定義(@types)のバージョン不一致
ライブラリ本体と @types パッケージのバージョンが合っていない場合、型定義と実際のAPIが食い違ってTS2554が発生することがあります。
型定義バージョンの確認と更新
# ライブラリと@typesのバージョンを確認
npm list express @types/express
# @types を最新に更新
npm install @types/express@latest
# または特定バージョンに合わせる
npm install @types/express@4.18
ラッパー関数の作成
ライブラリのAPIが変更された際、すぐに全箇所を修正できない場合は、ラッパー関数を作成して段階的に移行する方法があります。
ラッパー関数で互換性を保つ
// ライブラリの新API
// declare function connect(options: ConnectionOptions): Connection;
// 旧APIと同じインターフェースのラッパー関数
function connectLegacy(host: string, port: number): Connection {
return connect({ host, port });
}
// 既存のコードはラッパーを使う(段階的に移行)
connectLegacy("localhost", 3000); // OK
正しい解決アプローチ
TS2554 エラーを解決する方法は複数あります。状況に応じて最適なアプローチを選びましょう。
1. オプショナル引数にする
引数を省略可能にしたい場合の最もシンプルな方法です。
オプショナル引数
// Before: 引数省略不可
function search(query: string, limit: number, offset: number): Result[] { ... }
// After: limit と offset を省略可能に
function search(query: string, limit?: number, offset?: number): Result[] {
const l = limit ?? 10;
const o = offset ?? 0;
// ...
}
2. デフォルト引数を使う
省略時にデフォルト値を使いたい場合に最適です。
デフォルト引数
function search(query: string, limit: number = 10, offset: number = 0): Result[] {
// limit と offset は常に number 型(undefined チェック不要)
// ...
}
search("TypeScript"); // OK: limit=10, offset=0
search("TypeScript", 20); // OK: limit=20, offset=0
search("TypeScript", 20, 5); // OK: limit=20, offset=5
3. rest パラメータを使う
不特定多数の引数を受け取りたい場合に使います。
rest パラメータ
function merge<T>(...objects: Partial<T>[]): T {
return Object.assign({}, ...objects) as T;
}
// 何個でもオブジェクトを渡せる
merge({ a: 1 }, { b: 2 }, { c: 3 }); // OK
4. オーバーロードを定義する
異なる引数パターンで異なる戻り値を返したい場合に使います。
オーバーロード
function createElement(tag: "input"): HTMLInputElement;
function createElement(tag: "div", className: string): HTMLDivElement;
function createElement(tag: string, className?: string): HTMLElement {
const el = document.createElement(tag);
if (className) el.className = className;
return el;
}
5. 引数をオブジェクトにまとめる(Options パターン)
引数が多い関数では、すべてをオブジェクトにまとめるのがベストプラクティスです。
Options パターン(ベストプラクティス)
// Bad: 引数が多く、順序を間違えやすい
function createUser(
name: string,
age: number,
email: string,
role: string,
active: boolean
): User { ... }
// Good: Options パターン
interface CreateUserOptions {
name: string;
age: number;
email: string;
role?: "admin" | "user";
active?: boolean;
}
function createUser(options: CreateUserOptions): User {
const { name, age, email, role = "user", active = true } = options;
// ...
}
// 引数の順序を気にせず、必要なものだけ渡せる
createUser({
name: "太郎",
age: 25,
email: "taro@example.com",
}); // OK: role と active はデフォルト値
6. 関数設計のベストプラクティス
| ルール |
理由 |
| 引数は3つ以下にする |
4つ以上は Options パターンを検討 |
| 必須引数を先に、オプショナルを後に |
TypeScriptの仕様上のルール |
| 破壊的変更を避ける |
新しい引数は常にオプショナルにする |
| デフォルト引数を活用する |
undefined チェックが不要になる |
| 可変長にはrestパラメータ |
型安全に可変長引数を受け取れる |
| boolean 引数は避ける |
Options パターンで名前付きにする |
実務でよくあるTS2554パターン10選
ここでは、実際の開発現場で頻繁に遭遇するTS2554パターンを10個厳選して紹介します。
パターン1:ライブラリ更新後の引数変更
ライブラリのメジャーアップデートでAPIが変わり、既存の呼び出しコードが壊れるパターンです。
パターン1:ライブラリ更新後
// axios v0.x: axios(url, config) - 2引数
// axios v1.x: axios(config) - 1引数(urlはconfigの中)
// 旧コード → TS2554の可能性
// 解決策:マイグレーションガイドに従って更新
axios({ url: "/api/users", method: "GET" }); // 新しいAPI
パターン2:コールバックの引数不一致
パターン2:コールバック引数不一致
type Handler = (req: Request, res: Response) => void;
function route(path: string, handler: Handler): void {
// handler を呼ぶ際に引数を正しく渡す
handler(req, res); // OK: 2引数
// TS2554: Expected 2 arguments, but got 1.
handler(req); // res を渡し忘れ
}
パターン3:super() の引数忘れ
パターン3:super() の引数忘れ
class HttpError extends Error {
statusCode: number;
constructor(statusCode: number, message: string) {
// TS2554: Expected 0-1 arguments, but got 0.
// super(); ← message を渡し忘れ
super(message); // OK: Error のコンストラクタに message を渡す
this.statusCode = statusCode;
}
}
パターン4:bind / call / apply の引数
パターン4:bind / call / apply
function greet(greeting: string, name: string): string {
return `${greeting}, ${name}!`;
}
// call: 第1引数は this、残りは関数の引数
greet.call(null, "Hello", "太郎"); // OK
// TS2554: Expected 3 arguments, but got 2.
greet.call(null, "Hello"); // name が足りない
// apply: 第2引数は配列
greet.apply(null, ["Hello", "太郎"]); // OK
// bind: 部分適用
const greetHello = greet.bind(null, "Hello");
greetHello("太郎"); // OK: "Hello, 太郎!"
パターン5:useCallback / useMemo の依存配列忘れ
パターン5:依存配列忘れ
// TS2554: Expected 2 arguments, but got 1.
const memoized = useMemo(() => expensiveCalc(data));
// 修正:依存配列を追加
const memoized = useMemo(() => expensiveCalc(data), [data]);
パターン6:Promise の resolve に値を渡し忘れ
パターン6:resolve の引数忘れ
// TS2554: Expected 1 arguments, but got 0.
const p = new Promise<string>((resolve) => {
resolve(); // string を渡す必要がある
});
// 修正
const p = new Promise<string>((resolve) => {
resolve("done"); // OK
});
パターン7:配列のスプレッドで固定引数関数を呼ぶ
パターン7:スプレッド展開
const args = [1, 2]; // number[] と推論
// TS2556: A spread argument must either have a tuple type
Math.max(...args);
// 修正:as const でタプルにする
const args2 = [1, 2] as const;
Math.max(...args2); // OK
パターン8:ジェネリック関数の型引数と通常引数の混同
パターン8:ジェネリクスの混同
function identity<T>(value: T): T {
return value;
}
// 型引数と通常引数は別物
identity<string>("hello"); // OK: 型引数1つ + 通常引数1つ
// TS2554: Expected 1 arguments, but got 2.
identity("hello", 42); // 通常引数は1つだけ
パターン9:条件分岐での関数呼び出し
パターン9:条件分岐での呼び出し
type Action =
| { type: "SET_NAME"; payload: string }
| { type: "SET_AGE"; payload: number };
function dispatch(action: Action): void { ... }
// TS2554: Expected 1 arguments, but got 2.
dispatch("SET_NAME", "太郎"); // Redux風だが、引数はオブジェクト1つ
// 修正
dispatch({ type: "SET_NAME", payload: "太郎" }); // OK
パターン10:テストモックでの引数不一致
パターン10:テストモック
// 実際の関数は3引数
function fetchData(url: string, method: string, headers: Record<string, string>): Promise<unknown> {
// ...
}
// テストで呼ぶ際に引数を省略してしまう
// TS2554: Expected 3 arguments, but got 1.
fetchData("/api/test");
// 修正:テスト用のデフォルト値を用意
fetchData("/api/test", "GET", {}); // OK
よくある質問(FAQ)
Q. TS2554エラーとはどういう意味ですか?
A. 関数の呼び出し時に渡した引数の数が、関数定義の引数数と一致しない場合に発生します。Expected N arguments, but got Mのメッセージです。引数が少ない場合は必須引数の追加、多い場合は余分な引数の削除が必要です。
Q. 引数を省略できるようにするにはどうすればよいですか?
A. デフォルト値を設定する(param = "default")かオプショナル引数にする(param?: string)ことで省略可能になります。オプショナル引数は末尾に配置する必要があり、必須引数の後に置けません。また...argsの可変長引数を使うことで任意の数の引数を受け取れます。
Q. オーバーロードを定義しているのにTS2554が出ます。なぜですか?
A. オーバーロードの実装シグネチャ(最後のfunction宣言)が公開シグネチャの全パターンをカバーしていない可能性があります。実装シグネチャのパラメータ型は全てのオーバーロードシグネチャの和集合になるよう定義してください。実装シグネチャは外部から直接呼べないため、それが見えたらオーバーロード定義を確認してください。
まとめ
TypeScriptの TS2554(Expected N arguments, but got M)エラーは、関数呼び出し時の引数の数が定義と一致しないときに発生するエラーです。この記事で解説した内容を振り返りましょう。
TS2554 エラー解決のポイント
- エラーメッセージを正確に読む:Expected N(期待値)と got M(実際の値)を確認する
- 引数が多い場合:余分な引数を削除する、または rest パラメータで可変長にする
- 引数が少ない場合:不足引数を追加する、またはオプショナル / デフォルト引数にする
- オプショナル引数(?):省略時は undefined、デフォルト引数と使い分ける
- rest パラメータ(…args):可変長引数を型安全に受け取れる
- オーバーロード:異なる引数パターンで異なる戻り値を返す場合に使う
- Options パターン:引数が多い場合はオブジェクトにまとめるのがベストプラクティス
- React Hooks:useCallback / useMemo は依存配列(第2引数)が必須
- 外部ライブラリ:バージョンアップ後はCHANGELOGを確認する
- スプレッド展開:
as const でタプル型にすると固定引数関数にも渡せる
TS2554 vs TS2555 vs TS2556 の違い
引数の数に関連するエラーは TS2554 だけではありません。類似のエラーコードとの違いを確認しましょう。
| エラーコード |
メッセージ |
意味 |
典型例 |
| TS2554 |
Expected N arguments, but got M |
引数の数が一致しない |
fn(a, b) に fn(a) |
| TS2555 |
Expected at least N arguments, but got M |
最低N個の引数が必要 |
rest引数 + 必須引数の関数 |
| TS2556 |
A spread argument must either have a tuple type or be passed to a rest parameter |
スプレッド引数がタプルでない |
fn(...arr) で arr が可変長配列 |
関連記事
TypeScriptの型システムや他のエラーについて、さらに詳しく学びたい方は以下の記事もご覧ください。