【TypeScript】ローカル変数の使い方10選!

TypeScriptのローカル変数の基礎から応用までを図解したイメージTypeScript
この記事は約23分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

TypeScriptはJavaScriptの上位互換言語として、静的型付けやインターフェースなどの機能を持つことで、より堅牢で読みやすいコードを書くことができる言語です。

特に、ローカル変数の取り扱いは、TypeScriptの有力な機能の一つとして注目されています。

この記事では、TypeScriptでのローカル変数の使い方を10つの手法とサンプルコードを通して詳しく学ぶことができます。

初心者から上級者まで、段階を踏んでTypeScriptのローカル変数の知識と技術を高めていきましょう。

●TypeScriptのローカル変数とは

ローカル変数とは、特定の関数やブロック内でのみ利用可能な変数を指します。

これに対して、グローバル変数はプログラム全体でアクセス可能です。TypeScriptにおけるローカル変数は、スコープや型の概念と深く結びついています。

○ローカル変数の特徴

ローカル変数は、関数やブロック内で宣言され、その範囲内でのみ利用される変数です。

関数やブロックを出ると、その変数はメモリから解放されます。

特徴としては、メモリ効率が良く、外部からアクセスできないため情報隠蔽ができる点が挙げられます。

●ローカル変数の基本的な使い方

TypeScriptを学ぶうえで、ローカル変数の基本的な使い方を完全に理解することは非常に重要です。

ローカル変数は、関数やブロックスコープ内でのみ利用される変数であり、そのスコープを超えて参照することはできません。

ここでは、ローカル変数の基本的な使い方について詳しく説明し、実際のサンプルコードを交えて理解を深めていきましょう。

○サンプルコード1:ローカル変数の宣言と初期化

TypeScriptでは、letキーワードを使用してローカル変数を宣言します。

下記のコードは、ローカル変数messageを宣言し、文字列”Hello, TypeScript!”を代入する例です。

function greeting() {
    let message: string = "Hello, TypeScript!";  // このコードではmessageという名前のローカル変数を宣言し、文字列を代入しています。
    console.log(message);
}

greeting();

この例では、message変数はgreeting関数内でのみ参照可能であり、関数の外からはアクセスすることができません。

また、変数messageには型注釈stringが付けられており、この変数に文字列以外の値を代入しようとするとコンパイラがエラーを出力します。

実際に上記のコードを実行すると、コンソールには”Hello, TypeScript!”というメッセージが表示されるでしょう。

このように、ローカル変数はそのスコープ内でのみ動作し、スコープ外からはアクセスできないことを確認できます。

TypeScriptでは、変数の宣言と同時に初期化を行うことが一般的です。

初期化は、変数に初めて値を代入することを指します。

上述のコードのlet message: string = "Hello, TypeScript!";の部分が、変数の宣言と初期化を同時に行っている部分になります。

この知識を基に、TypeScriptでのプログラミング時に、適切なスコープで変数を管理することが、エラーや予期せぬ挙動を防ぐための鍵となります。

特に大規模なプロジェクトやチームでの開発時には、変数のスコープを適切に管理することで、バグの発生を大きく減少させることが期待できます。

○サンプルコード2:関数内でのローカル変数のスコープ

関数の内部で変数を宣言すると、その変数は関数のスコープ内でのみ有効となります。

これを「ローカル変数」と呼びます。関数の外部からは直接アクセスすることができません。

この特性を理解することは、バグを防ぐ上で非常に重要です。

関数内でローカル変数を宣言して利用するサンプルコードを紹介します。

function showLocalVariable() {
    let localVariable = "これはローカル変数です。";
    console.log(localVariable);
}

showLocalVariable(); // この関数呼び出し時にローカル変数が表示される
console.log(localVariable); // エラーになる

このコードでは、showLocalVariableという関数内でlocalVariableというローカル変数を宣言しています。この例では、関数内でローカル変数を表示しています。

しかし、関数の外部からlocalVariableを表示しようとすると、エラーが発生します。これは、localVariableshowLocalVariable関数のスコープ内でのみ有効だからです。

関数を呼び出すと、コンソールには「これはローカル変数です。」と表示されます。

しかし、関数の外部でローカル変数を参照しようとすると、ReferenceError: localVariable is not definedというエラーが表示されます。

このように、ローカル変数はその名の通り、宣言された関数の内部でのみ有効な変数です。

関数外部からアクセスしようとするとエラーとなるため、意図しない変数の上書きやアクセスを防ぐことができます。

●ローカル変数の応用的な使い方

TypeScriptにおいて、変数の活用はコーディングの効率と品質を向上させる鍵となります。

特にローカル変数は、関数内部でのみアクセス可能な変数であり、関数外からは参照できません。

ここでは、ローカル変数を更に活用して、より高度なコーディング技術を身につける方法について説明します。

○サンプルコード3:変数の型注釈

TypeScriptは静的型付け言語であり、変数に型を注釈することができます。

この機能を使用することで、コンパイル時に型の間違いをキャッチでき、バグを未然に防ぐことが可能です。

関数内部でローカル変数に型注釈を付ける例を紹介します。

function showDetails() {
  // 数値型のローカル変数を宣言
  let age: number = 25;

  // 文字列型のローカル変数を宣言
  let name: string = "Taro";

  console.log(`名前は${name}、年齢は${age}歳です。`);
}

このコードでは、ageという変数にnumber型の注釈を付けて、整数値を代入しています。

同様に、nameという変数にstring型の注釈を付け、文字列を代入しています。

もしage変数に文字列を代入しようとすると、TypeScriptのコンパイラはエラーを発生させて、この間違いを指摘してくれます。

このように、型注釈はコードの品質を向上させる大切なツールとなります。

上記のコードを実行すると、コンソールに「名前はTaro、年齢は25歳です。」という文が表示されます。

○サンプルコード4:letとconstの違い

TypeScriptにおいて、変数を宣言する際には、主にletconstの2つのキーワードを使用します。

これらはJavaScriptにも存在する概念ですが、TypeScriptでは、静的型の制約と組み合わせることで、より安全で効率的なコードを書くことができます。

ここでは、これら2つのキーワードの違いと、それぞれの使用シチュエーションをサンプルコードを交えて紹介します。

このコードでは、letキーワードを使用して変数valueを宣言しています。

この例では、valueに最初に1を代入し、その後、値を2に変更しています。

let value: number = 1;
console.log(value); // 1

value = 2;
console.log(value); // 2

letを使用して宣言された変数は、再代入が可能です。

そのため、値が変更される可能性がある変数を宣言する際にはletを使用します。

一方、このコードでは、constキーワードを使用して変数fixedValueを宣言しています。

この例では、fixedValueに1を代入しており、その後のコードで再代入を試みるとエラーとなります。

const fixedValue: number = 1;
console.log(fixedValue); // 1

// fixedValue = 2; // エラー: 再代入はできません。

constを使用して宣言された変数は、再代入が不可能です。

変数の値が変わることなく固定されている場合、または、再代入することなく、その値を安全に維持したい場合にconstを使用します。

○サンプルコード5:デストラクチャリング代入

TypeScriptでは、JavaScriptの機能として提供されるデストラクチャリング代入を使用することができます。

デストラクチャリング代入は、配列やオブジェクトの中身を一度に複数の変数に代入することができる非常に強力な機能です。

ここでは、TypeScriptにおけるデストラクチャリング代入の方法とその使用例を詳しく解説します。

まず、基本的なデストラクチャリング代入のサンプルコードを見てみましょう。

// 配列のデストラクチャリング代入
let [a, b] = [1, 2];
console.log(a);  // 1
console.log(b);  // 2

// オブジェクトのデストラクチャリング代入
let {x, y} = {x: 10, y: 20};
console.log(x);  // 10
console.log(y);  // 20

このコードでは、配列とオブジェクトのデストラクチャリング代入を使っています。

この例では、[a, b] = [1, 2]の部分で、配列の1番目と2番目の要素がそれぞれaとbに代入されています。

同様に、{x, y} = {x: 10, y: 20}の部分では、オブジェクトのxプロパティとyプロパティがそれぞれxとyに代入されています。

このデストラクチャリング代入を使用すると、複数の変数に一度に代入することができ、コードの可読性や効率が向上します。

さらに、デストラクチャリング代入を使った応用的な使い方の一例として、関数の戻り値の代入に使用する方法を見てみましょう。

function getPerson() {
    return {
        firstName: "Taro",
        lastName: "Yamada",
        age: 30
    };
}

let {firstName, lastName, age} = getPerson();
console.log(firstName);  // Taro
console.log(lastName);   // Yamada
console.log(age);        // 30

このコードでは、getPerson関数がオブジェクトを返しており、その返されたオブジェクトのプロパティをデストラクチャリング代入を使って複数の変数に代入しています。

このように、関数の戻り値を複数の変数に代入する場面でデストラクチャリング代入は非常に便利です。

以上のサンプルコードを見ると、デストラクチャリング代入を使用することで、複数の変数への代入を一度に行ったり、関数の戻り値を効率的にハンドリングしたりすることができることがわかります。

実際に上記のコードを実行すると、期待通りの結果が得られることが確認できます。

すなわち、最初のサンプルコードでは、aとbには1と2が、xとyには10と20が代入され、それぞれの変数の内容がコンソールに出力されます。

また、2つ目のサンプルコードでは、getPerson関数から返されるオブジェクトのプロパティが、それぞれfirstName、lastName、ageの変数に代入され、コンソールにそれらの値が出力されます。

●関数内での変数の使い方

関数内での変数は、関数の実行中のみアクセス可能な変数です。関数が終了すると、その変数は破棄され、再利用はできません。

これは、外部からアクセスできないため、データを保護するのに役立ちます。

○サンプルコード6:クロージャとローカル変数

クロージャは、関数とその関数が作成されたレキシカル環境の組み合わせです。

クロージャを使用すると、関数外部からはアクセスできない変数にアクセスできるようになります。

これにより、データの隠蔽や状態の保持など、さまざまなプログラミングパターンの実装が可能になります。

このコードでは、クロージャを使ってカウンター関数を作成しています。

この例では、createCounter関数が返す関数をcounter変数に代入し、counterを呼び出すたびにカウントが増加しています。

function createCounter() {
    let count = 0; // ローカル変数
    return function() {
        count++;
        return count;
    };
}

const counter = createCounter();

console.log(counter()); // 1を返す
console.log(counter()); // 2を返す

このサンプルコードを実行すると、最初のconsole.log(counter());は1を、次のconsole.log(counter());は2を表示します。

count変数はcreateCounter関数の内部にあり、外部からは直接アクセスできません。

しかし、クロージャによって、返された関数からはcount変数にアクセスできます。

この仕組みを利用することで、変数を外部から保護しつつ、特定の関数経由でその変数を操作することができます。

このような使い方は、モジュールパターンやデザインパターンにおいても見られ、プライベートな変数を持つオブジェクトを作成するのに役立ちます。

ここでの重要なポイントは、クロージャを理解することで、TypeScriptやJavaScriptの変数の振る舞いを深く理解し、より効果的なコードを書くことができるようになることです。

○サンプルコード7:再帰関数とローカル変数

再帰関数は、関数が自分自身を呼び出すことで、特定の問題を解決する方法を指します。

再帰関数は、特に計算が連続するような処理や、データの階層構造を探索する際などに非常に役立ちます。

再帰関数の中でローカル変数を使用することで、呼び出し毎にその関数内での変数の値が保持され、効率的な処理を実現することが可能です。

このコードでは、再帰関数を使用して、指定された数までの階乗を計算する例を取り上げます。

この例では、関数factorialが自分自身を呼び出して階乗の計算を行い、ローカル変数resultを使用して計算結果を保持しています。

function factorial(n: number): number {
  // ベースケース
  if (n === 0) return 1;

  // 再帰的に関数を呼び出し、ローカル変数resultに結果を代入
  const result: number = n * factorial(n - 1);

  return result;
}

const num: number = 5;
const factResult: number = factorial(num);
console.log(`${num}の階乗は${factResult}です。`);

上記のコードでは、再帰関数factorialを定義しており、関数の引数nが0の場合、1を返すことで再帰の終了条件(ベースケース)としています。

これは、0の階乗が1であるための定義に基づきます。

ベースケースを定義することは、再帰関数が無限に繰り返されないようにするために重要です。

次に、nが0でない場合、関数は自分自身を再帰的に呼び出します。

このとき、呼び出しの際にn - 1を引数として渡しています。この処理を繰り返すことで、階乗の計算が行われます。

実行すると、このコードは「5の階乗は120です。」という結果をコンソールに出力します。

このように再帰関数とローカル変数を組み合わせることで、複雑な計算や処理を効率的に行うことができます。

●高度な使い方とテクニック

○サンプルコード8:ローカル変数と型ガード

TypeScriptには、「型ガード」という強力な機能があります。

型ガードを使用することで、特定のコードブロック内での変数の型を確定させることができます。

これにより、開発者はその変数が持っているであろうプロパティやメソッドを安全にアクセスすることが可能になります。

型ガードの一例として、typeofinstanceof、ユーザー定義型ガードなどがあります。

それでは、ローカル変数を使用してtypeofによる型ガードの一例を取り上げます。

function processInput(input: string | number) {
    // このコードではtypeofを使って型ガードしています。この例ではinputがstring型かどうかをチェックしています。
    if (typeof input === 'string') {
        // ここではinputはstringとして扱われる
        console.log(input.toUpperCase());  // 文字列のメソッドを安全に使用できる
    } else {
        // ここではinputはnumberとして扱われる
        console.log(input.toFixed(2));  // 数字のメソッドを安全に使用できる
    }
}

上記のコードのprocessInput関数は、文字列または数値のどちらかを引数として受け取るように設計されています。

しかし、文字列特有のメソッドや数値特有のメソッドを使用する前に、その引数が実際にどの型かを判断する必要があります。

このときtypeofによる型ガードを使用することで、引数inputの型を確定させ、それぞれの型に特有のメソッドを安全に使用することができます。

このコードを実行すると、processInput関数に文字列を渡すとその文字列が大文字に変換されてコンソールに出力されます。

また、数値を渡すとその数値が小数点第2位までの形式に変換されてコンソールに出力されます。

たとえば、processInput("hello")を実行すると、コンソールにHELLOと出力されます。

また、processInput(3.14159)を実行すると、コンソールに3.14と出力されます。

○サンプルコード9:ジェネリクスとローカル変数

ジェネリクスは、TypeScriptの強力な機能の1つであり、型の再利用を可能にすることで、柔軟性と型安全性を両立させることができます。

ジェネリクスをローカル変数と組み合わせることで、より汎用的な関数やクラスを作成することができます。

このコードではジェネリクスを使って関数を定義しています。

この例では、ジェネリック関数identityを作成して、それをローカル変数に代入しています。

function identity<T>(arg: T): T {
    // ここでのargはジェネリクス型Tの変数となります。
    return arg;
}

// number型のローカル変数をジェネリクス関数を使用して定義
let myNumber: number = identity<number>(123);

// string型のローカル変数をジェネリクス関数を使用して定義
let myString: string = identity<string>("Hello, TypeScript!");

このサンプルコードでは、identity関数を使用して異なる型のローカル変数を生成しています。

identity関数は、入力として受け取った引数をそのまま返すだけのシンプルな関数ですが、ジェネリクスを使うことで様々な型で使用することができます。

このコードを実行すると、myNumber変数には123という数字が、myString変数には"Hello, TypeScript!"という文字列が格納されます。

ジェネリクスの<T>を利用することで、関数の引数や返り値の型を柔軟に定義できるため、多種多様な型でこの関数を使用することが可能です。

○サンプルコード10:ローカル変数の型推論

TypeScriptは静的型付け言語であるため、変数や関数、クラスなどの要素に型を付けることができます。

しかし、TypeScriptはスマートであり、開発者が変数に明示的に型を付けなくても、コードの文脈に基づいてその変数の型を推論することができるのです。

この特性を利用すると、冗長な型注釈を書く手間を省きつつ、安全にコードを書くことが可能となります。

それでは、具体的なサンプルコードを見ていきましょう。

let message = "こんにちは、TypeScript!";
let numberValue = 123;

このコードでは、message変数に文字列を代入しています。

この例では、明示的にmessage変数にstring型を付けていませんが、TypeScriptは右側の値(”こんにちは、TypeScript!”)をもとにmessage変数が文字列型であると自動的に推論します。

同様に、numberValueも右側の値(123)を基に数値型であると推論されます。

それでは、この推論の結果を確認してみましょう。

次のようにコードを追加し、型を調べることができます。

console.log(typeof message); // string
console.log(typeof numberValue); // number

上記のコードを実行すると、それぞれの変数の型が出力されます。

結果、messagestringとして、numberValuenumberとして認識されていることが確認できます。

さらに詳しい型の推論の動作を見てみましょう。

下記のコードはオブジェクトに関するものです。

let user = {
    name: "Taro",
    age: 25
};

この例では、user変数は2つのプロパティを持ったオブジェクトとして推論されます。

nameプロパティはstring型、ageプロパティはnumber型としてそれぞれ推論されます。

もちろん、この情報も利用して、オブジェクト内の各プロパティの型を確認することができます。

●ローカル変数の注意点と対処法

TypeScriptのローカル変数の利用時、初心者や中級者のプログラマーが直面する可能性のある一般的な問題や落とし穴を識別し、それらの問題に対する適切な対処法を提供します。

下記の情報は、プロフェッショナルなコーディングスキルを目指すあなたにとって、非常に役立つものとなるでしょう。

○変数の影響範囲に関する問題

ローカル変数は、宣言された関数の中だけで有効ですが、それが意図せず他の箇所に影響を与える場合があります。

このような問題の原因は、変数のスコープや、既存の変数との名前の衝突、変数の持ち越し等が考えられます。

この問題を避けるためのサンプルコードを紹介します。

function exampleFunction() {
    let localVariable = "ローカル変数です";
    console.log(localVariable); // ローカル変数です
}

exampleFunction();
console.log(localVariable); // エラー: localVariableは定義されていません

このコードでは、localVariableは関数exampleFunction内でのみ有効であり、関数の外からアクセスすることはできません。

そのため、関数外でのlocalVariableのログ出力はエラーとなります。

このようなエラーを避けるためには、変数のスコープを正確に理解し、適切な場所でのみ変数を使用することが重要です。

○再代入による誤動作

letキーワードを使用して宣言されたローカル変数は、再代入可能です。

これが意図しない再代入による誤動作の原因となる場合があります。

この問題を避けるためのサンプルコードを紹介します。

function calculateTotalPrice(price: number, tax: number) {
    let totalPrice = price;
    totalPrice = totalPrice + totalPrice * tax;
    console.log(`合計金額は${totalPrice}円です`);
}

calculateTotalPrice(100, 0.1); // 合計金額は210円です

このコードでは、税込みの合計金額を計算していますが、totalPriceに誤って税率を2回加算してしまった結果、意図しない合計金額が出力される問題が発生しています。

このような誤動作を避けるためには、再代入の必要がない場合はconstキーワードを使用して変数を宣言することが推奨されます。

また、コードのロジックをしっかりと確認し、テストを行うことも重要です。

○型の不一致

TypeScriptは静的型付け言語であるため、変数に予期しない型の値が代入されるとコンパイルエラーが発生します。

ローカル変数を使用する際には、変数の型を明確に指定することが推奨されます。

この問題を避けるためのサンプルコードを紹介します。

function greet(name: string) {
    console.log(`こんにちは、${name}さん!`);
}

greet("太郎");       // こんにちは、太郎さん!
greet(12345);       // エラー: '12345'の型は'number'ですが、'string'型の引数を期待しています。

このコードでは、greet関数の引数namestring型として定義されています。

したがって、number型の値を渡すとコンパイルエラーが発生します。

●ローカル変数のカスタマイズ方法

TypeScriptのローカル変数は、その特性や設定によってさまざまなカスタマイズが可能です。

ここでは、そのカスタマイズの方法やテクニックをいくつか紹介します。

○デフォルト値の設定

関数のパラメータにローカル変数を使用する際、デフォルト値を設定することができます。

デフォルト値は、関数が引数なしで呼び出された場合に使用される値です。

function greet(name: string = "ゲスト") {
    console.log("こんにちは、" + name + "さん!");
}

greet(); // このコードでは、nameパラメータにデフォルト値として"ゲスト"が設定されています。関数が引数なしで呼び出されると、"こんにちは、ゲストさん!"と表示されます。

上記の例を見ると、greet()関数は引数が提供されなかった場合、デフォルトの”ゲスト”という名前を使用して挨拶を返します。

実際に実行すると、「こんにちは、ゲストさん!」と出力されます。

○条件演算子を使用したカスタマイズ

ローカル変数の値に応じて処理を変更したい場合、条件演算子を利用すると効率的に処理をカスタマイズすることができます。

function priceCalc(price: number, isMember: boolean) {
    const discount = isMember ? price * 0.9 : price; // このコードでは、isMemberの真偽値を使って、価格に割引を適用するか決定しています。この例では、isMemberがtrueの場合、価格の90%を返します。
    return discount;
}

const result = priceCalc(1000, true);

上記の例では、priceCalc()関数内で条件演算子を使用して、メンバーである場合は10%の割引を適用しています。

実際に実行すると、メンバーの場合は価格が900になります。

○テンプレートリテラルを使用した文字列のカスタマイズ

TypeScriptでは、バッククォート(`)を使用したテンプレートリテラルを利用することで、変数の値を文字列内に埋め込むことができます。

const userName = "太郎";
const message = `こんにちは、${userName}さん!`; // このコードでは、テンプレートリテラルを使って、変数userNameの値を文字列内に埋め込んでいます。この例では、"こんにちは、太郎さん!"という文字列が生成されます。

上記の例では、テンプレートリテラルを使用して、userName変数の値を文字列に埋め込んでいます。

この方法を使うと、動的に文字列を生成することが容易になります。実際に実行すると、”こんにちは、太郎さん!”という文字列が出力されます。

まとめ

TypeScriptを学ぶ中で、ローカル変数の知識はコーディングの基盤となります。

この記事を通じて、TypeScriptのローカル変数に関する基礎から応用、さらには上級技術までを理解したことで、より効果的でプロフェッショナルなコードを書く力が身についたことでしょう。

この記事を読み終えたあなたは、TypeScriptのローカル変数の使い方10選を完璧にマスターした初心者から上級者へのステップアップを達成したことでしょう。

今後のプログラミングの旅に、この知識が大いに役立つことを願っています。