プログラミングの必須知識である「関数」について、基礎概念からTypeScriptでの実践的な書き方、モダン開発で主流の「関数型プログラミング」までを網羅しました。
実務で役立つ組み込み関数や初心者が陥りやすい注意点も具体例を交えて解説します。
プログラミングの変数について詳しく知りたい人は「プログラミングの変数とは?意味・命名規則・TypeScriptの型まで完全ガイド」を一読ください。
プログラミングの関数とは?
プログラミングの学習を進めていくと、「変数」の次に必ずぶつかる大きな壁が「関数」です。
インターネットで「プログラミング 関数とは」と検索したり、学校の「情報 プログラミング 関数」の授業で初めて触れたりして、概念に戸惑う方は非常に多いです。
しかし、プログラミング初心者の方でも心配はいりません。
関数は決して難しい数学の概念ではなく、プログラムを効率よく綺麗に書く必須ツールです。
ここでは、TypeScriptを用いて関数の基本概念から実務での注意点まで解説します。
- 関数とは「一連の処理をまとめた便利な自動販売機」
- 混同注意!「関数」と「変数」の決定的な違い
関数とは「一連の処理をまとめた便利な自動販売機」
関数とは、一言で表すと「決まった一連の処理をまとめた便利なパッケージ(自動販売機)」のようなものです。
自動販売機をイメージしてみてください。
「お金(データ)」を入れて「ボタン」を押すと、内部で「金額の計算や在庫の確認(処理)」が行われ、最終的に「ジュース(結果)」が出てきます。
プログラミングの関数も同じ仕組みです。
- 引数(ひきすう): 自動販売機に入れるお金(関数に渡すデータ)
- 処理: 内部で行われる計算や動作
- 戻り値(もどりち): 出てくるジュース(関数から返ってくる結果)
このように、よく使う処理を「関数」としてまとめておくことで、同じコードを何度も書く手間が省け(再利用性)、後から修正する際も1箇所直すだけで済む(保守性)というメリットがあります。
初心者が実務で一番よくやってしまうミスが、「1つの関数にアレもコレもと処理を詰め込みすぎてしまうこと」です。
1つの関数は「1つの仕事だけをする」ように小さく分けるのが鉄則です。
また、TypeScript特有の落とし穴として、引数と戻り値の「型(Type)」を書き忘れる(またはanyにしてしまう)というものがあります。
これを怠ると、思わぬデータが渡された時にバグを引き起こします。
// ⭕ 良い例:自動販売機関数(引数と戻り値の型がしっかり定義されている)
// money(お金)と drinkName(飲み物の名前)を受け取り、string(文字列)を返す
function buyDrink(money: number, drinkName: string): string {
const price = 150; // ジュースの価格設定
if (money >= price) {
const change = money - price;
return `${drinkName}を買いました! お釣りは${change}円です。`;
} else {
return `お金が足りません。${price}円入れてください。`;
}
}
// 関数の呼び出し(自動販売機を使う)
const result1 = buyDrink(200, "コーラ");
console.log(result1); // 出力: コーラを買いました! お釣りは50円です。
const result2 = buyDrink(100, "お茶");
console.log(result2); // 出力: お金が足りません。150円入れてください。
// ❌ 実務でNGな書き方(型が指定されていない・anyになっている)
// どんなデータが入ってくるか分からず、TypeScriptのメリットが完全に死んでしまう
// function badBuyDrink(money: any, drinkName: any) { ... }混同注意!「関数」と「変数」の決定的な違い
学習初期に多くの方が悩むのが関数と変数の違いです。
この2つは名前が似ていますが、役割は明確に異なります。
- 変数(Variable)=「名詞(データを入れる箱)」
- 例:「現在のポイント」「ユーザーの名前」「商品の価格」など、情報を記憶しておくためのものです。
- 関数(Function)=「動詞(処理を行う機械)」
- 例:「ポイントを追加する」「ユーザー情報を取得する」「消費税を計算する」など、特定の動作を実行するためのものです。
ここで初心者が必ず一度はハマる実務的な落とし穴が、「関数の実行結果(戻り値)が欲しいのに、関数そのものを変数に入れてしまう(()をつけ忘れる)」というミスです。
関数を使う(実行する)時は、必ず名前の後ろに()をつける必要があります。
()がないと、「機械を動かした結果」ではなく「機械そのもの」のデータが渡されてしまい、後続のプログラムがクラッシュしてしまいます。
// 【変数】ただのデータ(名詞)
const basePrice: number = 1000;
// 【関数】処理のまとまり(動詞)
function getTaxIncludedPrice(): number {
return basePrice * 1.1; // 10%の消費税を計算して返す
}
// ⭕ 正しい使い方:関数に () をつけて「実行」し、その結果を変数に入れる
const finalPrice: number = getTaxIncludedPrice();
console.log(finalPrice); // 出力: 1100
// ❌ よくある初心者のミス: () をつけ忘れる
// 関数を実行せず、関数という「機械自体」を代入しようとしてしまう
// const wrongPrice: number = getTaxIncludedPrice;
// 🚨 TypeScriptエラー: 型 '() => number' を型 'number' に割り当てることはできません。
// 💡 命名規則のコツ
// 実務では、一目で違いがわかるように
// 変数名は名詞(例: price, userData)
// 関数名は動詞から始める(例: calculatePrice(), getUserData())
// というルールを守るのがベストプラクティスです。プログラミングの変数について詳しく知りたい人は「プログラミングの変数とは?意味・命名規則・TypeScriptの型まで完全ガイド」を一読ください。
【TypeScript】関数の基本的な書き方と種類
TypeScript(およびベースとなるJavaScript)には、関数を作るための書き方がいくつか存在します。
書き方によって特徴や動作が少し異なるため、実務でコードを読む際に混乱しないよう、基本を押さえておくことが重要です。
ここでは、昔から使われている伝統的な関数の書き方、現代のフロントエンド開発(Reactなど)で主流となっている最新の書き方、TypeScriptならではの「型」の付け方まで解説します。
- 基本となる関数の定義と呼び出し方
- 現代の開発で主流なアロー関数
- TypeScript特有の引数と戻り値の型定義
基本となる関数の定義と呼び出し方
まずは、他の多くのプログラミング言語でも馴染み深い 「関数宣言(function」 を使った書き方です。
function 関数名() { 処理 }という構文で記述します。
この書き方の特徴は、「ホイスティング(巻き上げ)」という仕様により、コードの下の方で定義した関数を上の方で呼び出してもエラーにならないという点です。
初心者がつまずきやすいのが、「関数を定義しただけで、呼び出していないから何も起きない」というミスです。
関数は作っただけでは動きません。
必ず関数名()のようにカッコをつけて呼び出す必要があります。
// 1. 関数の定義(宣言)
// functionキーワードを使って、挨拶を表示する関数を作成
function sayHello() {
console.log("こんにちは!TypeScriptの世界へようこそ。");
}
// 2. 関数の呼び出し(実行)
// カッコ () をつけないと実行されません
sayHello(); // 出力: こんにちは!TypeScriptの世界へようこそ。
// 💡 豆知識(巻き上げ)
// functionキーワードで作った関数は、定義する前に呼び出しても動きます(実務では少し読みづらくなる原因にもなります)
callBeforeDefine(); // 出力: 呼ばれました!
function callBeforeDefine() {
console.log("呼ばれました!");
}現代の開発で主流なアロー関数
現在のTypeScript開発やReactなどのモダンなフレームワークにおいて、よく使われている関数の書き方が「アロー関数」です。
その名の通り、=>(矢印:アロー)を使って記述します。
functionキーワードを使わず、関数を「データ」のように変数(const)に代入する形で定義するのが特徴です。
アロー関数はfunction宣言と違い、「ホイスティング(巻き上げ)」が起きません。
そのため、定義する前に呼び出そうとするとエラーになります。
「なぜかエラーが出る!」と焦る初心者が多いですが、実務では「上から下へコードを読んでいけば、必ず先に関数が定義されている」という状態になり、むしろコードが読みやすくなるため、現在はこちらのアロー関数が積極的に採用されています。
// アロー関数の定義
// () => { 処理 } という形を作り、constで変数に代入する
const sayGoodbye = () => {
console.log("さようなら!また明日。");
};
// 呼び出し方は同じ
sayGoodbye(); // 出力: さようなら!また明日。
// ❌ よくあるミス:定義する前に呼び出すとエラーになる(巻き上げされない)
// calculateTotal(); // 🚨 エラー: 'calculateTotal' が初期化される前にアクセスできません。
const calculateTotal = () => {
console.log("合計を計算します");
};TypeScript特有の引数と戻り値の型定義
ここまでの関数はJavaScriptでも同じように書けます。
しかし、TypeScriptの強みは、関数に対して「どんなデータを受け取り(引数)」「どんなデータを返すのか(戻り値)」というルール(型)を厳格に決められることです。
- 引数の型:
(変数名: 型) - 戻り値の型:
(): 型 => { ... }またはfunction (): 型 { ... }
TypeScript初心者が実務でよくやってしまうミスが、「戻り値の型を省略してしまうこと」です。
TypeScriptは賢いので、戻り値の型を書かなくても推論してくれます。
しかし、複雑な処理を書いているうちに「数値を返すはずが、間違って未定義(undefined)を返す処理になってしまっていた」というバグが起きやすくなります。
実務では、「引数と戻り値の型は、必ず明示的に書く」のが堅牢なコードを保つベストプラクティスです。
// ⭕ 良い例:引数と戻り値にしっかり型を指定したアロー関数
// price(数値) と taxRate(数値) を受け取り、最終的な計算結果(数値)を返す
const getTaxIncludedPrice = (price: number, taxRate: number): number => {
return price * taxRate;
};
const finalPrice = getTaxIncludedPrice(1000, 1.1);
console.log(finalPrice); // 出力: 1100
// ❌ 悪い例(実務でバグを生む原因)
// 戻り値の型(: number)を書き忘れている。
// もし内部の計算ミスで文字列を返してしまっても、関数定義の段階では気づきにくい。
const badCalculate = (a: number, b: number) => {
// return a + b; のつもりが...
return "計算結果は " + (a + b); // 文字列になってしまった!
};
// ❌ さらに悪い例:引数に any 型を使う(TypeScriptの意味がなくなる)
const worstCalculate = (a: any, b: any): any => {
return a + b;
};TypeScript(JavaScript)の標準関数一覧
プログラミングで特定の処理を実現したいとき、「もしかして、すでに誰かが作った便利な関数があるのでは?」と考えるのは良い視点です。
インターネットで「プログラミング 関数 一覧」と検索して、使える機能を調べるのは実務でも日常茶飯事です。
TypeScript(およびベースとなるJavaScript)には、開発者がゼロから処理を書かなくても済むよう、最初から言語自体に用意されている「標準関数(組み込み関数)」が数多く存在します。
※オブジェクトに紐づく標準関数のことは「メソッド」とも呼ばれます。
ここでは、実務で使う文字列・配列操作の関数とゲームやアニメーションで活躍する数学関数を厳選して紹介します。
- 文字列や配列を操作する便利な組み込み関数
- 複雑な計算を助ける数学関数(三角関数・乱数など)
文字列や配列を操作する便利な組み込み関数
Web開発において、画面に表示するテキスト(文字列)を加工したり、サーバーから受け取ったデータの一覧(配列)を並び替えたりする処理は避けて通れません。
TypeScriptには、これらを一瞬で処理できる標準関数が備わっています。
- 文字列操作
replace()(文字の置換)、split()(文字の分割)、includes()(含まれているか判定)など - 配列操作
map()(全要素の加工)、filter()(条件に合う要素の抽出)、push()(末尾に追加)など
初心者が実務で高確率で引き起こすバグが、「破壊的メソッド」と「非破壊的メソッド」の混同です。
例えば、配列を並び替えるsort()は「破壊的」であり、元のデータそのものを書き換えてしまいます。
一方、新しく加工した配列を作るmap()は「非破壊的」であり、元のデータはそのまま残ります。
実務では、元のデータをうっかり書き換えてしまうと予測不能なバグに繋がるため、非破壊的なメソッド(map,filterなど)を優先して使うのが現代のベストプラクティスです。
// --- 配列操作の例(非破壊的メソッドの活用) ---
// ユーザーの年齢一覧(数値の配列)
const userAges: number[] = [18, 25, 30, 16, 42];
// 【filter関数】20歳以上のユーザーだけを抽出して「新しい配列」を作る
// age => age >= 20 というアロー関数を引数として渡しています
const adultAges: number[] = userAges.filter(age => age >= 20);
console.log(adultAges); // 出力: [25, 30, 42]
console.log(userAges); // 出力: [18, 25, 30, 16, 42] (元の配列は壊れていない!安全!)
// --- 文字列操作の例 ---
const message: string = "TypeScriptは難しいです。";
// 【replace関数】指定した文字を別の文字に置き換える
const positiveMessage: string = message.replace("難しい", "楽しい");
console.log(positiveMessage); // 出力: TypeScriptは楽しいです。複雑な計算を助ける数学関数(三角関数・乱数など)
数式を使った複雑な計算も、自分で一から実装する必要はありません。
TypeScriptにはMath(マス)という、数学計算に特化した便利な標準関数の集まりが用意されています。
- 丸め込み処理
Math.floor()(切り捨て)、Math.ceil()(切り上げ)、Math.round()(四捨五入) - 乱数(ランダム)
Math.random() - 三角関数など
Math.sin()、Math.cos()、Math.PI(円周率)
ここでの注意点は2つあります。
1つ目は、Math.random()はそのままでは「0以上1未満の小数(例: 0.352…)」しか出ないということです。
サイコロのように「1〜6の整数」が欲しい場合、自分で計算式を組み立てる必要があります。
2つ目は、プログラミングの三角関数の引数は、角度(360度)ではなく「ラジアン(弧度法)」で渡さなければならないという点です。
これを忘れてMath.sin(90)と書いてしまい、「計算結果がおかしい!」とパニックになる初心者が非常に多いです。
// --- 乱数(ランダムな整数)を生成する ---
// 1から指定した最大値までのランダムな整数を返す関数
const getRandomNumber = (max: number): number => {
// Math.random() で 0~0.999... を出し、maxを掛けて切り捨てることで整数を作る
return Math.floor(Math.random() * max) + 1;
};
const diceRoll: number = getRandomNumber(6); // 1〜6のサイコロ
console.log(`サイコロの目は ${diceRoll} です!`);
// --- 三角関数を使う際の注意点 ---
const angle: number = 90; // 90度
// ❌ よくあるミス:角度をそのまま渡してしまう
// const wrongSin = Math.sin(angle);
// ⭕ 正しいやり方:角度(度数法)をラジアン(弧度法)に変換してから渡す
// 変換公式: ラジアン = 角度 * (円周率 / 180)
const radian: number = angle * (Math.PI / 180);
const correctSin: number = Math.sin(radian);
console.log(`90度のサイン値は ${correctSin} です`); // 出力: 90度のサイン値は 1 です関数型プログラミングとは?
近年、Reactなどのモダンなフロントエンド開発が主流になるにつれ、「関数型プログラミング」という言葉を耳にする機会が増えました。
「関数型プログラミングとは何か?」「難しそうだけど学ぶ必要があるの?」と疑問に思う方も多いでしょう。
関数型プログラミングとは、プログラムを「数学的な関数の組み合わせ」として構築していくスタイルのことです。
ここでは、プログラミング入門者に向けて、関数型プログラミングの基礎、具体的な関数型プログラミング例までTypeScriptを使ってわかりやすく解説します。
- 関数型プログラミングの基礎概念
- オブジェクト指向プログラミングとの違い
関数型プログラミングの基礎概念
関数型プログラミングを理解する上で、2つの基礎概念があります。
それが「純粋関数」と「不変性」です。
- 純粋関数
同じ引数(入力)を与えれば、必ず同じ戻り値(出力)を返し、関数の外側にあるデータ(グローバル変数など)を一切変更しない関数のこと。 - 不変性(イミュータビリティ)
一度作成したデータ(変数や配列、オブジェクト)の中身を、後から直接書き換えない(破壊しない)というルール。
実務で関数型プログラミングを取り入れようとした初心者がよく陥るミスが、「配列やオブジェクトを直接書き換えてしまう(破壊的メソッドの使用)」ことです。
例えば、配列にデータを追加する際、TypeScript(JavaScript)標準のpush()メソッドを使うと、元の配列自体が書き換わってしまいます。
関数型プログラミングでは、元のデータを壊さず、スプレッド構文(...)などを使って「新しい配列」を作成して返すのが基本ルールです。
// ❌ 悪い例(純粋関数ではない・不変性を破っている)
let globalTotal = 0;
const impureAdd = (num: number): number => {
globalTotal += num; // 外側の変数を書き換えている(副作用)
return globalTotal;
};
const users = ["田中", "佐藤"];
const addUsersBad = (newUserName: string) => {
users.push(newUserName); // 元の配列を直接書き換えている(破壊的変更)
};
// ⭕ 良い例(純粋関数・不変性を保っている)
// 外側の変数に依存せず、引数だけで計算を完結させている
const pureAdd = (a: number, b: number): number => {
return a + b;
};
// スプレッド構文を使い、元の配列はそのままに「新しい配列」を作って返す
const addUsersGood = (currentUsers: string[], newUserName: string): string[] => {
return [...currentUsers, newUserName];
};
const updatedUsers = addUsersGood(["田中", "佐藤"], "鈴木");
// 出力: ["田中", "佐藤", "鈴木"] (元の ["田中", "佐藤"] は無傷のまま)オブジェクト指向プログラミングとの違い
プログラミングの学習において、関数 型 プログラミング オブジェクト 指向(OOP)の違いを理解することは重要です。
- オブジェクト指向プログラミング (OOP)
データ(状態)と、それを操作する関数(振る舞い)を「クラス」という一つのまとまり(オブジェクト)にカプセル化します。
オブジェクト自身が「自分の状態を書き換える」のが基本です。 - 関数型プログラミング (FP)
「データ」と「処理(関数)」を完全に切り離して考えます。
データはただの箱(書き換え不可)であり、関数はそのデータを引数として受け取り、新しいデータに変換して返すだけの役割を持ちます。
TypeScriptはオブジェクト指向も関数型も両方書けるマルチパラダイム言語です。
そのため、「クラスベースのコードと関数型のコードを中途半端に混ぜてしまう」という設計ミスが実務で頻発します。
例えば、classの中でthis.stateを書き換えているのに、一部のメソッドだけ純粋関数のように振る舞わせようとすると、他の開発者が「状態管理のルール」を把握できずバグの温床になります。
チームで開発する際は、どちらのパラダイムを主軸にするか統一することが重要です。
// --- オブジェクト指向の例(データと処理がセット。状態を書き換える) ---
class UserOOP {
constructor(public name: string, public age: number) {}
// 自分自身の状態(プロパティ)を直接書き換える
haveBirthday() {
this.age += 1;
}
}
const user1 = new UserOOP("田中", 20);
user1.haveBirthday(); // user1の中身が直接 21歳 に変更される
// --- 関数型プログラミングの例(データと処理を分離。新しいデータを返す) ---
// データはただの型定義
type UserFP = { readonly name: string; readonly age: number };
const user2: UserFP = { name: "佐藤", age: 20 };
// 処理は独立した純粋関数。引数としてデータを受け取り、新しいオブジェクトを返す
const haveBirthdayFP = (user: UserFP): UserFP => {
return { ...user, age: user.age + 1 };
};
const updatedUser2 = haveBirthdayFP(user2);
// user2 自体は 20歳のまま。updatedUser2 という新しい 21歳のデータが作られる関数型プログラミングのメリット
関数型プログラミングのメリットは、コードの「予測可能性」と「テストのしやすさ」に尽きます。
純粋関数は外の世界(グローバル変数やデータベースなど)の状態に依存せず、引数だけで結果が決まります。
そのため、「いつ、どこで、誰が実行しても、必ず同じ結果になる」という安心感があります。
予期せぬタイミングで変数が上書きされるバグ(副作用によるバグ)が激減するため、大規模なアプリケーションでも安全に開発を進めることができます。
実務におけるメリットの一つが「テストコードの書きやすさ」ですが、初心者は「不変性」を徹底できていないため、テストが失敗することがよくあります。
関数内で外部のAPIを直接叩いていたり、Date.now()のような実行するたびに結果が変わるものを直接使ってしまうと、純粋関数ではなくなりテストが困難になります。
// ❌ テストしづらい関数(外部の環境や時間に依存している)
const isWeekendBad = (): boolean => {
const today = new Date().getDay(); // 実行する日によって結果が変わる!
return today === 0 || today === 6;
};
// ⭕ 関数型プログラミングの利点を活かしたテストしやすい純粋関数
// 「判定したい日付」を引数として受け取るようにする
const isWeekendGood = (date: Date): boolean => {
const day = date.getDay();
return day === 0 || day === 6;
};
// 💡 テスト時のイメージ(引数を与えれば結果が100%予測できるためテストが簡単)
const saturday = new Date("2026-05-23"); // 土曜日
console.log(isWeekendGood(saturday)); // 必ず true になる関数型プログラミングのデメリット
最大の障壁は「学習コストの高さ」です。
オブジェクト指向に慣れ親しんだエンジニアにとって、「変数を上書きしてはいけない」「ループ(for文)を使わずにmapやreduceを使う」というルールは、最初は窮屈に感じます。
また、新しいデータを毎回生成するため、無駄なオブジェクトのコピーが大量に発生し、メモリ使用量やパフォーマンスに悪影響を与える可能性もあります。
関数型に憧れる初心者が実務で一番やってしまうのが、「関数型の記法を過剰に使いすぎ、かえってコードを読解不能にしてしまう」ことです。
特にreduceを複雑に使い回したコードは、他のチームメンバーにとって解読が難しくなります。
関数型のルールを守ることは大切ですが、「可読性」を犠牲にしてまで無理に1行で書くのは本末転倒です。
type Product = { name: string; price: number; inStock: boolean };
const cart: Product[] = [
{ name: "ノート", price: 200, inStock: true },
{ name: "ペン", price: 150, inStock: true },
{ name: "消しゴム", price: 100, inStock: false },
];
// ❌ デメリット:やりすぎた関数型の書き方(複雑なreduceチェーン)
// 初心者は「for文を使わない」ことに固執して、難解なコードを書きがち
const totalStockPriceBad = cart.reduce((acc, item) => {
return item.inStock ? acc + item.price : acc;
}, 0);
// ⭕ 実務で推奨される、可読性の高い関数型の書き方
// 無理に1つにまとめず、filterとmapなどで「言葉のように」処理を分ける
const totalStockPriceGood = cart
.filter(item => item.inStock) // まず在庫があるものだけを絞り込む
.map(item => item.price) // 次に価格だけの配列にする
.reduce((sum, price) => sum + price, 0); // 最後に合計する
console.log(totalStockPriceGood); // 出力: 350TypeScriptと関数型プログラミングの相性
「関数型プログラミング」に興味を持ち、インターネットで「関数型プログラミング言語」や「関数型プログラミング言語一覧」と検索すると、Haskell(ハスケル)やScala(スカラ)といった本格的な言語がヒットします。
しかし、実務でWebフロントエンドやバックエンドを開発するエンジニアにとって、今からそれらの言語をゼロから学ぶのはハードルが高いかもしれません。
そこで注目されているのがTypeScriptです。
実はTypeScriptは、「関数型 プログラミング言語 おすすめ」として紹介されることも多いほど、関数型プログラミングと高い親和性を持っています。
ここでは、TypeScriptで関数型プログラミングをどのように実践するのか、Reactなどのモダンな技術とどう結びついているのかを解説します。
- TypeScriptは関数型プログラミング言語として使える?
- Reactなどのモダンフレームワークと関数型の関係
TypeScriptは関数型プログラミング言語として使える?
結論から言うと、TypeScriptは関数型プログラミング言語として十分に使うことができます。
厳密には、TypeScriptはオブジェクト指向も関数型も書ける「マルチパラダイム言語」です。
しかし、関数を変数に代入したり、引数として渡したりできる「第一級関数(ファーストクラス関数)」の性質を備えているため、関数型のスタイルを自然に記述できます。
さらに、TypeScriptの「型システム」を活用することで、関数型プログラミングの肝である「不変性(イミュータビリティ)」をサポートできます。
TypeScriptで関数型プログラミングを始めようとした際、実務でよく陥るミスが「デフォルトのままでは配列やオブジェクトが変更可能(ミュータブル)であること」を忘れてしまう点です。
関数型のルール(データを書き換えない)を人間の注意だけで守るのは困難です。
TypeScriptの強みを活かし、readonly修飾子やas constを使って「書き換えようとしたらコンパイルエラーになる」仕組みを意図的に作る必要があります。
// ❌ 悪い例:TypeScriptの型を使っているが、中身が書き換え可能(関数型に反する)
type MutableUser = { name: string; age: number };
const user1: MutableUser = { name: "田中", age: 25 };
// 関数を通さずとも、どこからでも直接書き換えられてしまう(バグの原因)
user1.age = 26;
// ⭕ 良い例:readonly を使って「不変(イミュータブル)」を保証する
type ImmutableUser = { readonly name: string; readonly age: number };
const user2: ImmutableUser = { name: "佐藤", age: 30 };
// 🚨 user2.age = 31; // TypeScriptが「読み取り専用プロパティであるため、'age' に代入することはできません」とエラーを出して守ってくれる!
// 新しいデータが必要な場合は、純粋関数とスプレッド構文で「新しいオブジェクト」を作る
const haveBirthday = (user: ImmutableUser): ImmutableUser => {
return { ...user, age: user.age + 1 };
};
const updatedUser = haveBirthday(user2);
console.log(updatedUser.age); // 出力: 31まとめ
分かりやすいようにまとめを記載します。
- 関数は一連の処理をまとめたものであり、「データを入れる箱」である変数とは役割が異なる。
- 現代のTypeScript開発では、ホイスティング(巻き上げ)が起きない「アロー関数」の使用が主流である。
- 安全なコードを保つため、関数の「引数」と「戻り値」には必ず型(Type)を明示する。
- 実務の配列操作では、元のデータを直接書き換えない非破壊的な標準関数(
mapやfilterなど)を優先して使用する。 - 関数型プログラミングは、「純粋関数」とデータの「不変性」を基礎とし、バグの少ない予測可能なコードを実現する手法である。
- TypeScriptは関数型のアプローチと非常に相性が良く、Reactなどの最新フレームワークを用いた開発において必須のスキルとなる。
よくある質問(FAQ)
プログラミングの関数とは簡単に言うと何ですか?
決まった処理の手順をひとまとめにした「便利なパッケージ(自動販売機のようなもの)」のことです。
プログラミングでは、同じ計算や処理を何度も行う場面が多々あります。
毎回ゼロからコードを書くのではなく、よく使う一連の処理に名前をつけてまとめたものが「関数」です。
必要な時にその名前を呼び出すだけで、何度でも同じ処理を実行させることができます。
引数(ひきすう)と戻り値(もどりち)とは何ですか?
自動販売機で例えると、引数は「入れるお金(関数に渡すデータ)」、戻り値は「出てくるジュース(関数が返してくる処理結果)」です。
関数は単独で動くこともありますが、基本的には「外から材料(引数)を受け取り、中で加工・計算をして、結果(戻り値)を外に返す」という役割を担います。
// price(引数)を受け取り、消費税を計算して数値(戻り値)を返す関数
function calculateTax(price: number): number {
return price * 0.1; // return で戻り値を返す
}「関数」と「メソッド」の違いは何ですか?
根本的な処理の仕組みは同じですが、「どこに属しているか」という位置づけが異なります。
単独で存在しており、どこからでも直接呼び出せるものを「関数(Function)」と呼びます。
一方、特定のデータ(オブジェクトやクラス)の中に組み込まれており、そのデータに紐付いた処理を行う関数のことを「メソッド(Method)」と呼びます。
例えばconsole.log()のlog()は、consoleというオブジェクトに属するメソッドです。
なぜわざわざ関数を作るのですか?(メリットは何ですか?)
最大のメリットは「コードの再利用」と「修正のしやすさ(保守性)」です。
同じ処理を複数の場所にバラバラに書いていると、もし仕様変更(例:消費税が10%から15%になった等)があった際、すべての箇所を探して修正しなければなりません。
関数にまとめておけば、関数の内部を1箇所修正するだけで、プログラム全体の計算結果を安全かつ一瞬でアップデートできます。
関数名の付け方にルールはありますか?
関数は「処理(動作)」を表すため、「動詞」から始めるのが世界共通のルールです。
データを保存する変数は「名詞(例:price)」で名付けますが、関数は「データを取得する(getData)」「計算する(calculatePrice)」「真偽を判定する(isUserValid)」のように名付けます。
TypeScriptでは、変数と同じく2単語目以降の頭文字を大文字にする「キャメルケース」を使うのが標準的です。

