TypeScript | 基礎文法:関数の基礎 – 関数の引数型

TypeScript
スポンサーリンク

関数の引数型って何をしているのか

まず一番シンプルに言うと、「この関数は、どんな“形”の値を受け取るのかを約束する」のが引数型です。

function add(a: number, b: number): number {
  return a + b;
}
TypeScript

ここで a: numberb: number が「引数の型」です。
add は、number 型を2つ受け取る関数ですよ」と宣言しているわけです。

この「約束」を書いておくことで、

  • 間違った型の値を渡そうとしたときにコンパイルエラーになる
  • 関数の使い方が、型を見るだけで分かる

という状態になります。


引数型の基本的な書き方

1つの引数に型を付ける

function greet(name: string): void {
  console.log(`Hello, ${name}`);
}

greet("Taro");   // OK
// greet(123);  // エラー: number は string に渡せない
TypeScript

name: string の部分が、「この引数は string 型でなければならない」という宣言です。
型を書かなかった場合、引数は any とみなされてしまうので、TypeScript の恩恵がほぼ消えます。

複数引数の型

function createUser(name: string, age: number): { name: string; age: number } {
  return { name, age };
}

createUser("Taro", 20);   // OK
// createUser("Taro", "20"); // エラー
TypeScript

それぞれの引数に対して、名前: 型 の形で書いていきます。
「引数ごとに型を付ける」のが基本形です。


TypeScript は「引数の数」もチェックする

JavaScript との大きな違い

JavaScript では、引数の数が合っていなくても普通に実行されます。

function increment(n) {
  return n + 1;
}

increment(1, 2); // 余分な引数は無視される
increment();     // n は undefined になり、NaN になることも
TypeScript

TypeScript はここを厳密にチェックします。

function increment(n: number): number {
  return n + 1;
}

increment(1);      // OK
// increment();    // エラー: Expected 1 arguments, but got 0.
// increment(1, 2); // エラー: Expected 1 arguments, but got 2.
TypeScript

エラーメッセージの

Expected 1 arguments, but got 2.

は、「1個の引数を期待しているのに、2個渡されているよ」という意味です。
「数も型も合っているときだけ呼べる」というのが、TypeScript の関数呼び出しです。


オブジェクトを引数にする場合の型

オブジェクト引数に型を付ける

type User = {
  name: string;
  age: number;
};

function printUser(user: User): void {
  console.log(`${user.name} (${user.age})`);
}

printUser({ name: "Taro", age: 20 }); // OK
// printUser({ name: "Taro" });       // エラー: age が足りない
TypeScript

ここでは、user: User として「User 型のオブジェクト」を引数に受け取っています。
User 型の定義に従って、プロパティの有無や型がチェックされます。

分割代入と組み合わせる

function printUser2({ name, age }: User): void {
  console.log(`${name} (${age})`);
}
TypeScript

({ name, age }: User) は、
「User 型のオブジェクトを受け取り、その中から name と age を取り出す」という意味です。
「引数の形」と「中身の型」を同時に表現できる」ので、実務でもよく使われます。


配列を引数にする場合の型

配列全体を受け取る

function sum(numbers: number[]): number {
  return numbers.reduce((acc, n) => acc + n, 0);
}

sum([1, 2, 3]);        // OK
// sum(["1", "2"]);    // エラー: string[] は number[] に渡せない
TypeScript

numbers: number[] は、「number の配列」を受け取るという意味です。
配列の中身の型も、ちゃんとチェックされます。

配列の要素をオブジェクトにする

type Product = {
  name: string;
  price: number;
};

function total(products: Product[]): number {
  return products.reduce((sum, p) => sum + p.price, 0);
}
TypeScript

ここでは、「Product 型の配列」を受け取っています。
「配列の形」と「要素の形」を両方型で表現できる」のがポイントです。


optional 引数・デフォルト引数・rest 引数の型

optional 引数(あってもなくてもいい)

function greet(name: string, title?: string): void {
  if (title) {
    console.log(`${title} ${name}`);
  } else {
    console.log(name);
  }
}

greet("Taro");           // OK
greet("Taro", "Dr.");    // OK
TypeScript

title?: string は、「この引数は省略してもよい」という意味です。
型としては string | undefined に近いイメージになります。

デフォルト引数

function greet2(name: string, title: string = "Mr."): void {
  console.log(`${title} ${name}`);
}

greet2("Taro");          // "Mr. Taro"
greet2("Taro", "Dr.");   // "Dr. Taro"
TypeScript

デフォルト値を指定すると、その型が自動的に引数型として推論されます。
titlestring として扱われます。

可変長引数(rest 引数)

function sumAll(...numbers: number[]): number {
  return numbers.reduce((acc, n) => acc + n, 0);
}

sumAll(1, 2, 3);     // OK
sumAll(10, 20);      // OK
// sumAll(1, "2");   // エラー
TypeScript

...numbers: number[] は、「number をいくつでも受け取る」という意味です。
「何個来るか分からないけど、全部同じ型」というときに使います。


「引数型」をどう意識すると上達が早いか

一番大事なのは、「この関数は、どんな値を受け取る“つもり”なのかを、型で正直に書く」という意識です。

「ここは絶対に string じゃないと困る」なら string と書く。
「ここは省略されることもある」なら ? を付ける。
「オブジェクトの形が決まっている」なら、型(type / interface)を定義してそれを使う。

そうすると、TypeScript がこういうことを全部チェックしてくれます。

  • 引数の数が合っているか
  • 引数の型が合っているか
  • オブジェクトのプロパティが足りているか・余計なものがないか

関数を書くたびに、こう自分に問いかけてみてください。

「この関数は、本当はどんな“形”のデータを受け取りたいんだっけ?」

その答えを、引数型として素直に書いていく——
それが、関数の引数型を“使いこなす”ための一番の近道です。

タイトルとURLをコピーしました