このページでは、プログラミング初心者の方でも理解しやすいように、できるだけやさしい言葉を使って、TypeScriptにおける「メソッド」について詳しく解説します。
前提知識として、「プログラミング言語のクラス構文」というものがあることを少し聞いたことがある、ぐらいのイメージで読み進めていただければ大丈夫です。
【前提】そもそも「メソッド」とは?
メソッドとは、あるクラス(オブジェクト)の中で定義される「関数(処理のかたまり)」のことです。「関数」とほとんど同じ意味ですが、「クラスの中に入っている関数」を特別に「メソッド」と呼びます。
- 関数(function): 単体の処理のかたまり
- メソッド(method): クラスの一部として定義された関数
もし「クラス」や「オブジェクト」という言葉がまだピンとこない場合は、「設計図」と「それをもとに作られる実体」とイメージしてみてください。クラスは「設計図」、そこから作られる実体を「インスタンス(オブジェクト)」と呼びます。詳しくはこちら(参考 TypeScriptのクラス)
TypeScript:メソッド定義の基本構文
TypeScriptでは、JavaScriptにクラス構文(class)が追加されており、そこに「メソッド」を定義できます。基本構文は以下のようになります。
class MyClass { public myMethod(param: string): number { return param.length; } }
class MyClass:
public myMethod(param: string): number { ... }:
TypeScriptのメソッド定義は、基本的にはJavaScript(ES6以降)で導入されたクラス構文とほぼ同じです。つまり、JavaScriptがもともと持っているクラス構文やメソッド定義の書き方がベースになっています。
ただし、TypeScriptには型注釈(パラメータの型や戻り値の型指定など)や、アクセス修飾子(public, private, protected) が追加されています。そういった部分がJavaScriptにはないTypeScript独自の要素だと考えるとわかりやすいです。
アクセス修飾子 (public, private, protected)
public
の部分は、「このメソッドはどこからでも呼び出せますよ」という意味の アクセス修飾子 です。TypeScriptでは主に3種類あり、以下のようにクラスのプロパティ(変数)やメソッド(関数)に付けられます。
- public: どこからでもアクセス(呼び出し)可能。
- private: 同じクラスの中だけからアクセス可能。(クラスの外からは呼べない)
- protected: 同じクラスと継承(サブクラス)したクラスの中だけからアクセス可能。
初心者のうちは、まずは public
でメソッドを定義しておけばOKです。
メソッドを呼び出すときのイメージ 〜インスタンス化とは?〜
クラスは「設計図」なので、そのままでは実際に使えません。クラスから「インスタンス」(実体)を作って、そのインスタンスを通じてメソッドを呼び出します。これを 「インスタンス化」 といいます。
// 1. クラスの定義 class Greeter { public greet(name: string): void { console.log(`Hello, ${name}!`); } } // 2. インスタンスを作成(インスタンス化) const myGreeter = new Greeter(); // 3. メソッドを呼び出す myGreeter.greet("Alice"); // 「Hello, Alice!」 と表示される
new Greeter()
でクラスGreeter
の実体(インスタンス)が生成され、myGreeter
という変数に格納されます。myGreeter.greet("Alice")
のように、「インスタンス.メソッド名(引数)」 という書き方で、メソッドを呼び出します。
非同期処理を扱う「asyncメソッド」とは?
TypeScript(JavaScript)では、「非同期処理」 を扱うために async/await
という機能があります。
たとえば、サーバーにデータを取りにいく処理などは時間がかかるため、プログラムがそれを待っているあいだ他のことを停止してしまわないように、いわゆる「非同期」の仕組みが使われます。
class DataFetcher { public async fetchData(url: string): Promise<any> { // `async` を付けることで、このメソッドはPromiseを返すようになる const response = await fetch(url); // fetch は非同期関数 // `await` を使うと、その処理が終わるまで一旦待ってくれる return await response.json(); } } // 使い方 (async () => { const fetcher = new DataFetcher(); const data = await fetcher.fetchData("https://example.com/data.json"); console.log(data); })();
async
は「このメソッドは非同期処理を行うよ」という宣言です。await
は「Promiseを返す処理が終わるまで待ち合わせ」をするためのキーワードです。- これにより、見た目は「同期的(順番に処理が進んでいる)」なコードを書きながら、内部は非同期で動作させることができます。
「Promise」というのは、ざっくり言うと「非同期の結果がいつか返ってくることを約束するオブジェクト」のようなものです。実際には「非同期処理が成功した場合は成功の結果、失敗した場合はエラーを返す」という仕組みになっていますが、初学者のうちは「長い時間かかる処理でも、その結果をひとまとめに扱える仕組み」と考える程度で大丈夫です。
実践的なサンプル:商品を管理するクラス
ここまでの知識を応用して、商品情報を扱うクラスを作る例を示します。たとえば、オンラインストアのシステムなどをイメージしてください。(参考 TypeScriptのインターフェースとは?)
// Productという「型(インターフェース)」を用意 interface Product { id: number; name: string; price: number; } class ProductService { // クラスの中で共通して使う配列を用意(ここではproductsという変数) private products: Product[] = []; // 商品を追加するメソッド public addProduct(product: Product): void { this.products.push(product); } // 商品一覧を返すメソッド public getAllProducts(): Product[] { return this.products; } // IDを指定して商品を取得するメソッド public getProductById(productId: number): Product | undefined { return this.products.find((p) => p.id === productId); } // 非同期で在庫チェックをするメソッド public async checkInventory(productId: number): Promise<boolean> { // 擬似的な「サーバー問い合わせ」を再現するため、1秒待機している await new Promise((resolve) => setTimeout(resolve, 1000)); // ランダムにtrue/falseを返す(50%の確率で在庫あり) return Math.random() > 0.5; } } // === 実際に使ってみる === const productService = new ProductService(); // 商品を追加 productService.addProduct({ id: 1, name: "Book", price: 1000 }); productService.addProduct({ id: 2, name: "Pen", price: 100 }); // 追加された商品一覧を表示 console.log(productService.getAllProducts()); // IDが1の商品を取得してみる const product = productService.getProductById(1); console.log("ID=1の商品:", product); // 在庫チェック(非同期メソッド)の呼び出し (async () => { const hasInventory = await productService.checkInventory(1); console.log("ID=1に在庫があるか:", hasInventory); })();
サンプルコードで注目すべきポイント
private products: Product[] = [];
private
修飾子が付いた「クラス内の変数(プロパティ)」です。クラスの外からは直接アクセスできません。products
は配列(Product[]
)として初期化しています。- メソッドからは自由にアクセス・操作できますが、クラスの外から
productService.products
のように直接操作することはできません。
- メソッドの設計
addProduct
: 商品を配列に追加する。getAllProducts
: 登録されている商品を全部返す。getProductById
: IDに一致する商品を返す。checkInventory
: 在庫があるかを確認し、Promise(true or false)を返す非同期メソッド。
- オブジェクト指向の考え方
- データ(
products
)と、そのデータを扱うための処理(addProduct
,getProductById
など)が同じクラスにまとまっています。 - これが「オブジェクト指向」という考え方の基本で、設計図(クラス)を元に作られたモノ(インスタンス)に対して、メソッドを使って操作をします。
- データ(
- Q関数とメソッドはどう違うのですか?
- A
メソッドは、クラスやオブジェクトの一部として定義された関数のことです。関数(function) 自体は、クラスの外に定義するただの処理のかたまりです。
- Q戻り値の型指定は必ず必要ですか?
- A
TypeScriptでは、明示的に指定したほうがよいですが、型推論が働く場合は書かなくても動作はします。ただし、初心者のうちはできるだけ明示するのをおすすめします。よりコードがわかりやすくなります。
- Qasyncメソッドを使わずに非同期処理をするには?
- A
「Promiseを直接使う」や「コールバック関数を使う」など、いくつか方法があります。しかし、
async/await
はコードが読みやすいので、今から学ぶならasync/await
を優先的に覚えるとよいでしょう。