TypeScriptのクラス (class)
クラスは、JavaScript ES6で導入されたオブジェクト指向の構文機能です。TypeScriptはこれを基盤とし、型注釈とアクセス制御を追加することで、クラスのプロパティやメソッドに型制約が確実に適用されるようにしています。
1. クラスの基本的な構文
(1) プロパティの宣言とコンストラクタ
TypeScript では、JavaScript とは異なり、クラスのプロパティは使用前に宣言する必要があります:
TYPESCRIPT
class User {
// Property Declaration(TypeScript Requirements)
name: string;
age: number;
// Constructor
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// Methods
greet(): string {
return `Hello,I am${this.name},This year${this.age} years old`;
}
}
let user = new User("Charlie", 20);
console.log(user.greet()); // "Hello,I amCharlie,This year20 years old"
(2) プロパティを初期化するいくつかの方法
TYPESCRIPT
class Config {
// Method 1:Initialize directly upon declaration
host: string = "localhost";
port: number = 3000;
// Method 2:Initialization in the Constructor
env: string;
constructor(env: string) {
this.env = env;
}
// Method 3:Assert that it is not empty(!)——You promise to assign a value later.
data!: string;
}
let cfg = new Config("development");
cfg.data = "some data"; // Create First, Then Assign
🔥 よくある間違い: コンストラクタ内でプロパティが初期化も値の代入もされていない場合、TypeScript は(厳格モードにおいて)「プロパティが初期化されていない」というエラーを発生させます。
! アサーションを使用することでこの問題を回避できますが、そのプロパティに実際に値が代入されていることを確認してください。
2. アクセス修飾子
TypeScript の 3 つのアクセス修飾子は、プロパティやメソッドの可視性を制御します:
| 修飾子 | クラス内 | サブクラス | クラス外 |
|---|---|---|---|
public |
✅ | ✅ | ✅ |
protected |
✅ | ✅ | ❌ |
private |
✅ | ❌ | ❌ |
(1) public(デフォルト)
TYPESCRIPT
class Person {
public name: string; // public This is the default value.,Optional
public age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
let p = new Person("Charlie", 20);
console.log(p.name); // ✅ Accessible from outside the class
p.name = "Diana"; // ✅ Can be modified from outside the class
(2) 非公開
TYPESCRIPT
class BankAccount {
private balance: number;
constructor(initialBalance: number) {
this.balance = initialBalance;
}
public deposit(amount: number): void {
if (amount > 0) this.balance += amount;
}
public withdraw(amount: number): boolean {
if (amount > 0 && amount <= this.balance) {
this.balance -= amount;
return true;
}
return false;
}
public getBalance(): number {
return this.balance;
}
}
let account = new BankAccount(1000);
account.deposit(500);
account.withdraw(200);
console.log(account.getBalance()); // 1300
// account.balance; // ❌ private The property is not accessible from outside
// account.balance = 99999; // ❌ private Properties cannot be modified externally
(3) 保護対象
TYPESCRIPT
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
protected makeSound(sound: string): void {
console.log(`${this.name}:${sound}`);
}
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
public bark(): void {
this.makeSound("Woof!"); // ✅ Subclasses can access protected Methods
// console.log(this.name); // ✅ Subclasses can access protected Properties
}
}
let dog = new Dog("Wangcai");
dog.bark(); // "Wangcai:Woof!"
// dog.name; // ❌ protected The property is not accessible from outside
// dog.makeSound("Howl"); // ❌ protected This method cannot be called from outside the class.
(4) コンストラクタ引数の省略表記
TypeScript にはパラメータプロパティという機能があります。コンストラクタのパラメータの前に修飾子を付けることで、プロパティが自動的に宣言・初期化されます:
TYPESCRIPT
// Complete Syntax
class User1 {
public name: string;
private age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
// Abbreviation——The effect is exactly the same
class User2 {
constructor(
public name: string,
private age: number
) {}
}
let u = new User2("Charlie", 20);
console.log(u.name); // ✅ public
// console.log(u.age); // ❌ private
💡 ヒント: パラメータのプロパティを使用するとコードが簡潔になりますが、プロパティが多すぎると可読性が低下します。プロパティが3つ以下の場合は短縮表記を使用し、3つを超える場合は明示的に宣言してください。
3. readonly 修飾子
readonly 修飾子を持つプロパティには、宣言時またはコンストラクタ内でのみ値を割り当てることができます:
TYPESCRIPT
class Circle {
readonly radius: number;
constructor(radius: number) {
this.radius = radius; // ✅ You can assign values in the constructor
}
get area(): number {
return Math.PI * this.radius ** 2;
}
}
let circle = new Circle(5);
console.log(circle.area); // 78.54
// circle.radius = 10; // ❌ readonly Properties cannot be modified
(1) 読み取り専用プロパティとパラメータ付きプロパティ
TYPESCRIPT
class Config {
constructor(
readonly host: string,
readonly port: number
) {}
}
let cfg = new Config("localhost", 3000);
console.log(`${cfg.host}:${cfg.port}`); // "localhost:3000"
// cfg.host = "other"; // ❌ readonly
4. アクセサ(ゲッター/セッター)
アクセサを使用すると、プロパティの読み取りや書き込みの際に、独自のロジックを実行することができます:
(1) 基本的な構文
TYPESCRIPT
class Employee {
private _salary: number = 0;
// getter——Execute on read
get salary(): number {
return this._salary;
}
// setter——Perform validation during assignment
set salary(value: number) {
if (value < 0) {
throw new Error("Salaries cannot be negative.");
}
this._salary = value;
}
}
let emp = new Employee();
emp.salary = 8000; // Call setter
console.log(emp.salary); // Call getter → 8000
// emp.salary = -100; // ❌ Throw an error
(2) 読み取り専用プロパティ(ゲッターはあるがセッターはないもの)
TYPESCRIPT
class User {
constructor(
private firstName: string,
private lastName: string
) {}
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
// None setter → fullName It is read-only.
}
let user = new User("San", "Zhang");
console.log(user.fullName); // "San Zhang"
// user.fullName = "Si Li"; // ❌ None setter
▶ 例:温度換算ツール
TYPESCRIPT
class Temperature {
private _celsius: number = 0;
constructor(celsius: number) {
this._celsius = celsius;
}
get celsius(): number {
return this._celsius;
}
set celsius(value: number) {
if (value < -273.15) {
throw new Error("The temperature must not fall below absolute zero.(-273.15°C)");
}
this._celsius = value;
}
get fahrenheit(): number {
return this._celsius * 9 / 5 + 32;
}
set fahrenheit(value: number) {
this.celsius = (value - 32) * 5 / 9; // Reuse celsius Verification of
}
}
let temp = new Temperature(100);
console.log(`${temp.celsius}°C = ${temp.fahrenheit}°F`); // "100°C = 212°F"
temp.fahrenheit = 32;
console.log(`${temp.celsius}°C = ${temp.fahrenheit}°F`); // "0°C = 32°F"
出力:
TEXT
100°C = 212°F
0°C = 32°F
5. 静的メンバ
static 変更されたプロパティやメソッドは、インスタンスではなくクラス自体に属します:
(1) 静的プロパティとメソッド
TYPESCRIPT
class MathUtils {
static PI: number = 3.14159;
static circleArea(radius: number): number {
return MathUtils.PI * radius ** 2;
}
static clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
}
// No need to create an instance,Call directly using the class name
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.circleArea(5)); // 78.53975
console.log(MathUtils.clamp(150, 0, 100)); // 100
(2) 静的ブロック (TypeScript 5.0 / ES2022+)
TYPESCRIPT
class Config {
static host: string;
static port: number;
// Static Initialization Block
static {
Config.host = process.env.HOST ?? "localhost";
Config.port = Number(process.env.PORT) || 3000;
}
}
(3) 静的メンバとインスタンスメンバの違い
TYPESCRIPT
class Counter {
static totalCount: number = 0; // Shared by all instances
instanceCount: number = 0; // Each instance is independent
increment(): void {
Counter.totalCount++;
this.instanceCount++;
}
}
let c1 = new Counter();
let c2 = new Counter();
c1.increment();
c1.increment();
c2.increment();
console.log(`Examples1:${c1.instanceCount}`); // 2
console.log(`Examples2:${c2.instanceCount}`); // 1
console.log(`Total:${Counter.totalCount}`); // 3
❓ よくある質問
Q
private は実行時に本当にプライベートなのでしょうか?A いいえ。TypeScript の
private はコンパイル時のチェックに過ぎず、コンパイルされた JavaScript コード内ではプライベートプロパティに依然としてアクセス可能です。ES2022の#private構文(プライベートフィールド)こそが、真のランタイムのプライバシーを実現するものです。TypeScriptは#private: class C { #secret = 1; }もサポートしています。Q
private はいつ使い、protected はいつ使うべきですか?A
private は「そのクラス自身のみが必要とする」内部実装の詳細に使用します。protected は、「サブクラスもアクセスしたりオーバーライドしたりする必要があるかもしれない」メンバーに使用します。迷った場合は、まずは private から始めてください。必要に応じて後でいつでも protected に変更できます(制限を厳しくするよりも、許容範囲を広めに設定する方が安全です)。Q ゲッター/セッターと通常メソッドの違いは何ですか?
A ゲッター/セッターメソッドは、プロパティの読み書きをあたかも直接アクセスしているかのように見せかけますが(YIJIAN0PH)、実際には裏でカスタムロジックを実行しています。通常のメソッドは明示的な呼び出しが必要です(YIJIAN1PH)。外部に公開するプロパティ(バリデーションの実行やプロパティの計算など)にはゲッター/セッターを使用し、内部実装には通常のメソッドを使用することを推奨します。
Q
thisは静的メソッドで使用できますか?A 静的メソッド内では、
this refers to the class itself (not an instance). In static create() { return new this(); }, this is equal to the current class. However, this may be lost in arrow functions or callbacks—it is recommended to use the class name instead of this を使用できます。📖 まとめ
- TypeScript では、クラスではプロパティを使用する前に宣言する必要があります。プロパティは、宣言時に初期化したり、コンストラクタ内で代入したり、
!によってアサーションを行ったりすることができます。 - アクセス修飾子:public(デフォルト、クラス外からアクセス可能)、protected(サブクラスからアクセス可能)、private(クラス内部からのみアクセス可能)
- パラメータのプロパティにより、プロパティの宣言やコンストラクタでの代入の構文が簡略化されます
- 読み取り専用プロパティは、宣言時またはコンストラクタ内でのみ初期化できます
- ゲッター/セッターメソッドは、プロパティの読み取りや書き込み時にカスタムロジックを実行します。ゲッターはあってもセッターがない場合、そのプロパティは読み取り専用となります。
- 静的メンバーはインスタンスではなくクラス自体に属しており、
ClassName.memberを通じてアクセスされます。
📝 練習問題
- 基本問題(難易度 ⭐):
Rectangleクラス(width および height プロパティを持つ)を作成し、getArea()およびgetPerimeter()メソッドを実装してください。パラメータ化されたプロパティを使用して、コンストラクタを簡略化してください。 - 上級問題(難易度 ⭐⭐):
BankAccountクラスを作成してください。balanceを private にし、depositおよびwithdrawメソッドを介して操作を行えるようにし、ゲッターを使用して残高を読み取り専用として公開し、withdraw操作を行う前に残高が十分であることを確認してください。 - 課題(難易度:⭐⭐⭐):汎用クラス
Stack<T>を実装してください。プライベートな配列にデータを格納し、push、pop、peek、size メソッドを提供します。また、ゲッターを使用して size プロパティ(読み取り専用)を実装し、静的メソッドstatic fromArray<T>(items: T[]): Stack<T>を使用して、その配列からスタックを作成してください。



