Чи можна перевантажити (overload) конструктор?
1. Загальна ідея перевантаження конструктора
У TypeScript можна оголосити кілька сигнатур конструктора, але реалізувати - лише один (реальний) конструктор з перевірками всередині:
class User {
name: string;
age?: number;
// Перевантаження (type-level only)
constructor(name: string);
constructor(name: string, age: number);
// Реалізація одна
constructor(name: string, age?: number) {
this.name = name;
this.age = age;
}
}
const u1 = new User("Tim"); // працює
const u2 = new User("Alex", 25); // працює
const u3 = new User(); // Помилка: немає такого перевантаженняПеревантаження (
constructor(...)) вище - лише сигнатури типів. Останнійconstructor(...)з тілом - реальна реалізація.
2. Як це працює під капотом
TypeScript компілює все в один JavaScript-конструктор, а перевантаження потрібні лише для перевірки типів на етапі компіляції.
// TS
class User {
constructor(name: string);
constructor(name: string, age: number);
constructor(name: string, age?: number) {
console.log(name, age);
}
}Компілюється в JS:
class User {
constructor(name, age) {
console.log(name, age);
}
}Перевірки типів прибираються, залишається один конструктор.
3. Перевірка аргументів усередині конструктора
Оскільки JS не підтримує "реальні" перевантаження, усередині конструктора зазвичай роблять перевірки вручну:
class Point {
x: number;
y: number;
constructor(x: number);
constructor(x: number, y: number);
constructor(x: number, y?: number) {
if (y === undefined) {
this.x = this.y = x; // якщо передано один аргумент
} else {
this.x = x;
this.y = y;
}
}
}
new Point(5); // (5, 5)
new Point(5, 10); // (5, 10)4. Перевантаження з різними типами параметрів
Можна перевантажити конструктор за типами, а не лише за кількістю аргументів:
class FileData {
path: string;
buffer?: Uint8Array;
constructor(path: string);
constructor(buffer: Uint8Array);
constructor(value: string | Uint8Array) {
if (typeof value === "string") {
this.path = value;
} else {
this.buffer = value;
this.path = "memory.bin";
}
}
}
new FileData("file.txt"); // string
new FileData(new Uint8Array([1, 2])); // Uint8Array
new FileData(123); // Помилка типів5. Перевантаження через union-типи (альтернатива)
Іноді перевантаження можна замінити простим об'єднанням типів (|):
class User {
constructor(public name: string | number) {}
}
new User("Tim");
new User(123);Але при цьому TS не розрізняє сигнатури, і всередині конструктора потрібно вручну розбирати типи.
6. Перевантаження конструктора в базовому і успадкованому класі
Можна перевантажити конструктор у батьківському класі і викликати потрібний через super():
class Shape {
color: string;
constructor();
constructor(color: string);
constructor(color = "black") {
this.color = color;
}
}
class Circle extends Shape {
radius: number;
constructor(radius: number);
constructor(radius: number, color: string);
constructor(radius: number, color?: string) {
super(color);
this.radius = radius;
}
}
const c1 = new Circle(10);
const c2 = new Circle(10, "red");7. Важливий нюанс: перевантаження ≠ runtime-перевантаження
Усі сигнатури перевіряються лише компілятором і не існують у скомпільованому коді:
- TypeScript перевіряє правильну кількість і типи аргументів.
- JavaScript виконує єдиний конструктор з перевірками всередині.
- Не можна мати дві реалізації конструктора.
Підсумок
| Можливість | Підтримка | Коментар |
|---|---|---|
| Кілька сигнатур конструктора | Так | Перевіряються компілятором |
| Кілька реалізацій конструктора | Ні | Лише одна з тілом |
| Перевантаження за кількістю аргументів | Так | Через ? або перевірки |
| Перевантаження за типами | Так | Через об'єднання або сигнатури |
| Реальне runtime-перевантаження (як у C#/Java) | Ні | Не можна |
Перевірка типів при new | Так | Працює завдяки сигнатурам |
Коротко:
У TypeScript можна перевантажувати конструктори, але лише на рівні типів. Реалізація завжди одна, і всередині ти сам перевіряєш аргументи.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.