メインコンテンツまでスキップ

アクセス修飾子 (access modifier)

JavaやPHPなどの言語では、フィールドやメソッドにprivate, protected, publicを指定できます。JavaScriptでもprivateのようなプロパティを実現するためにプライベートクラスフィールドという仕様がありますが、Javaのようなアクセス修飾子とはやや様相が異なります。TypeScriptにはJava風のアクセス修飾子があります。

アクセス修飾子説明
(宣言なし)publicと同等
publicどこからもアクセス可能
protected自身のクラスとサブクラスからアクセス可能
private自身のクラスのみアクセス可能

アクセス修飾子を省略した場合はpublicになります。

アクセス修飾子は、フィールド、コンストラクタ、メソッドに宣言することができます。

public

publicアクセス修飾子はどこからもアクセス可能です。アクセス修飾子を省略した場合もpublicを指定したものと同等として扱われます。

ts
class Animal {
public name: string; // フィールドにpublicアクセス修飾子
 
// コンストラクターにpublicアクセス修飾子
public constructor(theName: string) {
this.name = theName;
}
 
// メソッドにpublicアクセス修飾子
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
// publicアクセス修飾子である`this.name`を使用することが可能
}
}
ts
class Animal {
public name: string; // フィールドにpublicアクセス修飾子
 
// コンストラクターにpublicアクセス修飾子
public constructor(theName: string) {
this.name = theName;
}
 
// メソッドにpublicアクセス修飾子
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
// publicアクセス修飾子である`this.name`を使用することが可能
}
}

gorillaを実装し、動作を確認してみます。

ts
const gorilla = new Animal("ゴリラ");
gorilla.move(10);
"ゴリラ moved 10m."
gorilla.name = "ゴリラゴリラ";
gorilla.move(20);
"ゴリラゴリラ moved 20m."
ts
const gorilla = new Animal("ゴリラ");
gorilla.move(10);
"ゴリラ moved 10m."
gorilla.name = "ゴリラゴリラ";
gorilla.move(20);
"ゴリラゴリラ moved 20m."

nameプロパティはpublic宣言されているため、インスタンスされた変数(gorilla)からの読み書きが可能になっています。「ゴリラ」から「ゴリラゴリラ」に変更することができます。

protected

protectedアクセス修飾子は自身のクラスとサブクラスからアクセス可能です。

Animalクラスmoveメソッドのアクセス修飾子をpublicからprotectedに変更しエラーを出してみます。

ts
class Animal {
public name: string;
 
public constructor(theName: string) {
this.name = theName;
}
 
// `public`から`protected`に変更
protected move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
 
const gorilla = new Animal("ゴリラ");
gorilla.move(10);
Property 'move' is protected and only accessible within class 'Animal' and its subclasses.2445Property 'move' is protected and only accessible within class 'Animal' and its subclasses.
ts
class Animal {
public name: string;
 
public constructor(theName: string) {
this.name = theName;
}
 
// `public`から`protected`に変更
protected move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
 
const gorilla = new Animal("ゴリラ");
gorilla.move(10);
Property 'move' is protected and only accessible within class 'Animal' and its subclasses.2445Property 'move' is protected and only accessible within class 'Animal' and its subclasses.

gorilla.move()メソッドはprotected宣言されているため、自身のクラスとサブクラスのみアクセスとなります。つまりインスタンスされたgorillaからはアクセスが拒否され、コンパイルエラーが発生します。

protectedで保護されたmove()メソッドを新たに実装し、10倍速く動くゴリラを作ってみます。

ts
class Animal {
public name: string;
 
public constructor(theName: string) {
this.name = theName;
}
 
// `public`から`protected`に変更
protected move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
 
class Gorilla extends Animal {
move(distanceInMeters: number) {
super.move(distanceInMeters * 10);
}
}
 
const gorilla = new Gorilla("速いゴリラ");
gorilla.move(10);
"速いゴリラ moved 100m."
ts
class Animal {
public name: string;
 
public constructor(theName: string) {
this.name = theName;
}
 
// `public`から`protected`に変更
protected move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
 
class Gorilla extends Animal {
move(distanceInMeters: number) {
super.move(distanceInMeters * 10);
}
}
 
const gorilla = new Gorilla("速いゴリラ");
gorilla.move(10);
"速いゴリラ moved 100m."

Animalスーパークラスを持つGorillaクラスを定義しmove()を実装しています。Gorillaクラスのmove()メソッド内でsuperキーワードを利用してスーパークラスのmove()メソッドを呼び出しています。

private

privateアクセス修飾子は自身のクラスのみアクセス可能です。

protected move()private move()に変更してみます。privateに変更されたことによりGorillaクラスのsuper.moveにアクセスすることが許されずエラーとなります。

ts
class Animal {
public name: string;
 
public constructor(theName: string) {
this.name = theName;
}
 
// `public`から`private`に変更
private move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
 
class Gorilla extends Animal {
Class 'Gorilla' incorrectly extends base class 'Animal'. Property 'move' is private in type 'Animal' but not in type 'Gorilla'.2415Class 'Gorilla' incorrectly extends base class 'Animal'. Property 'move' is private in type 'Animal' but not in type 'Gorilla'.
move(distanceInMeters: number) {
super.move(distanceInMeters * 10);
Property 'move' is private and only accessible within class 'Animal'.2341Property 'move' is private and only accessible within class 'Animal'.
}
}
ts
class Animal {
public name: string;
 
public constructor(theName: string) {
this.name = theName;
}
 
// `public`から`private`に変更
private move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
 
class Gorilla extends Animal {
Class 'Gorilla' incorrectly extends base class 'Animal'. Property 'move' is private in type 'Animal' but not in type 'Gorilla'.2415Class 'Gorilla' incorrectly extends base class 'Animal'. Property 'move' is private in type 'Animal' but not in type 'Gorilla'.
move(distanceInMeters: number) {
super.move(distanceInMeters * 10);
Property 'move' is private and only accessible within class 'Animal'.2341Property 'move' is private and only accessible within class 'Animal'.
}
}

privateメソッドの多くの使い方としては、自身のクラス内の長いコードを機能別に分ける時に利用します。

アクセス修飾子を変更する

クラスの継承時に、メソッドのアクセス修飾子を変更することができます。とはいえなんでも自由に変更できるのではなく、アクセス制限を緩める方向にだけ変更できます。つまりprotected > publicの方向への変更は可能ですがその逆はできません。

ts
class ProtectedClass {
protected doNothing(): void {
console.log("DO NOTHING");
}
}
 
class PublicClass extends ProtectedClass {
public doNothing(): void {
console.log("DO NOTHING");
}
}
ts
class ProtectedClass {
protected doNothing(): void {
console.log("DO NOTHING");
}
}
 
class PublicClass extends ProtectedClass {
public doNothing(): void {
console.log("DO NOTHING");
}
}

逆のpublic > protectedの実装はできません。

ts
class PublicClass {
public doNothing(): void {
console.log("DO NOTHING");
}
}
 
class ProtectedClass extends PublicClass {
Class 'ProtectedClass' incorrectly extends base class 'PublicClass'. Property 'doNothing' is protected in type 'ProtectedClass' but public in type 'PublicClass'.2415Class 'ProtectedClass' incorrectly extends base class 'PublicClass'. Property 'doNothing' is protected in type 'ProtectedClass' but public in type 'PublicClass'.
protected doNothing(): void {
console.log("DO NOTHING");
}
}
ts
class PublicClass {
public doNothing(): void {
console.log("DO NOTHING");
}
}
 
class ProtectedClass extends PublicClass {
Class 'ProtectedClass' incorrectly extends base class 'PublicClass'. Property 'doNothing' is protected in type 'ProtectedClass' but public in type 'PublicClass'.2415Class 'ProtectedClass' incorrectly extends base class 'PublicClass'. Property 'doNothing' is protected in type 'ProtectedClass' but public in type 'PublicClass'.
protected doNothing(): void {
console.log("DO NOTHING");
}
}