ゴール:「new させないクラス」に意味を持たせる感覚をつかむ
private constructor は一言でいうと、
「このクラスは、外から new してほしくない」と宣言するための仕組み
です。
「え、クラスって new して使うものでしょ?」と思うかもしれませんが、
あえて「new させない」ことで、設計がきれいになる場面がいくつかあります。
ここでは代表的な用途を、初心者向けにかみ砕いて説明していきます。
基本:private constructor とは何か
通常のコンストラクタとの違い
普通のクラスはこう書きます。
class User {
constructor(public name: string) {}
}
const u = new User("Taro"); // どこからでも new できる
TypeScriptコンストラクタが public(省略時のデフォルト)なので、
どのファイルからでも new User(...) ができます。
private constructor にするとこうなります。
class User {
private constructor(public name: string) {}
}
// const u = new User("Taro"); // エラー:コンストラクタが private なので外から new できない
TypeScriptこの時点で、
「このクラスは、クラスの外側からは new できない」
という制約がかかります。
では、そんなクラスをどうやって使うのか?
ここからが本題です。
用途1:シングルトン(インスタンスを1つだけにしたい)
「このクラスのインスタンスは1個だけでいい」パターン
シングルトンは、
「アプリ全体で、このクラスのインスタンスは1つだけにしたい」
というときの定番パターンです。
private constructor は、これを TypeScript で表現するときにとても相性がいいです。
class AppConfig {
private static instance: AppConfig | null = null;
private constructor(
public readonly apiEndpoint: string,
public readonly timeoutMs: number
) {}
static getInstance(): AppConfig {
if (this.instance === null) {
this.instance = new AppConfig("https://api.example.com", 5000);
}
return this.instance;
}
}
// 使う側
const config1 = AppConfig.getInstance();
const config2 = AppConfig.getInstance();
console.log(config1 === config2); // true(同じインスタンス)
TypeScriptここでのポイントは、
- コンストラクタが
privateなので、new AppConfig(...)は外からできない - 代わりに
static getInstance()経由でしかインスタンスを取れない getInstance()の中で「まだなければ作る・あればそれを返す」を管理している
ということです。
「勝手に new されると困るから、作り方をクラス自身が管理する」
そのための鍵が private constructor です。
なぜ private にすることが大事なのか
もしコンストラクタが public のままだと、
どこからでも new AppConfig(...) できてしまいます。
そうなると、
- 2つ目、3つ目のインスタンスが勝手に作られる
- 「本当に1つだけ」という前提が崩れる
- バグの原因になる(設定がバラバラになる、など)
private constructor にすることで、
「インスタンスの数や作り方を、クラス自身が完全にコントロールできる」
ようになります。
用途2:ファクトリメソッドで「作り方」を制御したい
直接 new させず、「こういう作り方だけ許す」と決めたい
例えば、日付を表すクラスを考えます。
class MyDate {
private constructor(
public readonly year: number,
public readonly month: number,
public readonly day: number
) {}
static fromYmd(ymd: string): MyDate {
const [y, m, d] = ymd.split("-").map(Number);
return new MyDate(y, m, d);
}
static today(): MyDate {
const now = new Date();
return new MyDate(
now.getFullYear(),
now.getMonth() + 1,
now.getDate()
);
}
}
TypeScriptここでは、
- コンストラクタは
privateなので、new MyDate(2024, 1, 1)は外からできない - 代わりに
fromYmd("2024-01-01")やtoday()といった
「意味のある作り方」だけを公開している
という設計になっています。
使う側はこうなります。
const d1 = MyDate.fromYmd("2024-01-01");
const d2 = MyDate.today();
TypeScript何がうれしいのか
private constructor にしておくと、
- 不正な値で new されるのを防げる
(例えば month に 13 を渡される、など) - 「このクラスはこういう作り方をしてほしい」という意図を
staticメソッドの名前で表現できる - 将来、内部表現を変えても、外側の呼び出し方を変えずに済む
といったメリットがあります。
「コンストラクタを隠して、“意味のある作り方”だけを公開する」
これが、private constructor+ファクトリメソッドの典型的な使い方です。
用途3:継承させたくない・ユーティリティクラスにしたい
「インスタンス化も継承もさせない」ユーティリティクラス
例えば、純粋なユーティリティクラスを作りたいとします。
class MathUtil {
private constructor() {} // インスタンス化禁止
static clamp(value: number, min: number, max: number): number {
return Math.min(max, Math.max(min, value));
}
static isEven(value: number): boolean {
return value % 2 === 0;
}
}
const x = MathUtil.clamp(10, 0, 5); // OK
// const m = new MathUtil(); // エラー:コンストラクタが private
TypeScriptここでの意図は、
- このクラスは「インスタンスを持つ意味がない」
- すべて
staticメソッドとして使ってほしい - だから
newされると困る
というものです。
private constructor にしておくことで、
「このクラスは“インスタンス化される前提ではない”」
という設計意図を、コードで強制できます。
継承もさせたくない場合
TypeScript では final のようなキーワードはありませんが、private constructor を使うと、継承も事実上できなくなります。
class Base {
private constructor() {}
}
// class Child extends Base {} // エラー:Base のコンストラクタにアクセスできない
TypeScript「このクラスは継承されることを想定していない」
という意思表示にもなります。
設計の視点:いつ private constructor を使うべきか
キーワードは「自由に new されると困るか?」
private constructor を使うか迷ったら、
自分にこう問いかけてみてください。
「このクラスは、どこからでも自由に new されていいだろうか?」
もし、
- インスタンスが1つだけであることが前提
- 作り方にルールがある(必ずバリデーションしたい、など)
- インスタンス化されること自体に意味がない(ユーティリティ)
- 継承されると設計が崩れる
といった事情があるなら、private constructor を検討する価値があります。
「コンストラクタを公開する=作り方を自由にする」ということ
コンストラクタを public のままにしておく、というのは、
「このクラスは、どこからどういう値で new されてもいいです」
と宣言しているのと同じです。
それで問題ないクラスもたくさんありますが、
そうでないクラスもあります。
private constructor は、
「このクラスの作り方は、クラス自身が管理する」
という設計を選ぶためのスイッチだと思ってください。
まとめ:private constructor を自分の言葉で整理すると
最後に、あなた自身の言葉でこうまとめてみてください。
private constructor は、
- クラスの外から
newできなくするための仕組み - シングルトンのように「インスタンスを1つだけ」にしたいとき
- ファクトリメソッド経由で「作り方を制御」したいとき
- ユーティリティクラスのように「インスタンス化させたくない」とき
- 継承させたくないクラスを作りたいとき
に使うと、設計がスッキリする。
今あなたが書いているクラスの中で、
「これは勝手に new されると困るな」
「本当は static メソッドだけで使ってほしいな」
「インスタンスは1個だけでいいのにな」
と感じるものがあれば、
一度 private constructor を試してみてください。
その瞬間から、
「ただのクラス」だったものが、「作り方までデザインされたクラス」
に変わっていきます。

