Злиття декларацій у TypeScript
Що таке об'єднання декларацій?
Об'єднання декларацій — це здатність TypeScript об'єднувати кілька декларацій з однаковим ім'ям в одне визначення. Це унікальна функція, яка не існує в більшості інших мов.
Об'єднання інтерфейсів
Найбільш поширена форма — кілька декларацій інтерфейсів з однаковим ім'ям об'єднуються:
interface User {
name: string;
}
interface User {
age: number;
}
interface User {
email: string;
}
// Усі три об'єднуються в:
// interface User {
// name: string;
// age: number;
// email: string;
// }
const user: User = {
name: "Alice",
age: 25,
email: "alice@example.com"
}; // Має мати ВСІ властивостіtype не може бути об'єднаний
type User = { name: string };
type User = { age: number }; // ❌ Помилка: Дублюючий ідентифікатор 'User'Це ключова різниця між interface і type.
Розширення модулів
Розширюйте існуючі модулі, додаючи декларації:
// Розширення Express Request
declare module "express" {
interface Request {
user?: {
id: string;
role: string;
};
}
}
// Тепер req.user доступний у всіх обробниках
app.get("/profile", (req, res) => {
console.log(req.user?.id); // ✅ TypeScript це розпізнає
});Розширення сторонніх бібліотек
// Додати власні матчери до Jest
declare module "@jest/expect" {
interface Matchers<R> {
toBeWithinRange(floor: number, ceiling: number): R;
}
}
// Розширення Window
declare global {
interface Window {
analytics: {
track(event: string, data?: object): void;
};
}
}
window.analytics.track("page_view"); // ✅Об'єднання простору імен
namespace Validation {
export function isEmail(value: string): boolean {
return /^[^@]+@[^@]+$/.test(value);
}
}
namespace Validation {
export function isPhone(value: string): boolean {
return /^\+?\d{10,}$/.test(value);
}
}
// Обидві функції доступні:
Validation.isEmail("test@test.com"); // ✅
Validation.isPhone("+380123456789"); // ✅Об'єднання перерахувань
enum Color {
Red = 0,
Green = 1,
}
enum Color {
Blue = 2,
Yellow = 3,
}
// Об'єднані: Color.Red, Color.Green, Color.Blue, Color.YellowПрактичні випадки використання
Додавання типів до бібліотек без типів
// custom.d.ts
declare module "untyped-library" {
export function doSomething(input: string): number;
export const VERSION: string;
}Змінні середовища
// env.d.ts
declare namespace NodeJS {
interface ProcessEnv {
NODE_ENV: "development" | "production" | "test";
DATABASE_URL: string;
JWT_SECRET: string;
PORT?: string;
}
}
process.env.DATABASE_URL; // ✅ Типізовано як рядокПравила об'єднання
| Декларація | Може об'єднуватися з |
|---|---|
| Інтерфейс | Інтерфейс ✅ |
| Простір імен | Простір імен ✅, Клас ✅, Функція ✅, Перерахування ✅ |
| Клас | Простір імен ✅ |
| Функція | Простір імен ✅ |
| Перерахування | Перерахування ✅, Простір імен ✅ |
| Псевдонім типу | Нічого ❌ |
Важливо:
Об'єднання декларацій найбільш корисне для розширення модулів — розширення типів сторонніх бібліотек. Об'єднання інтерфейсів також є причиною, чому interface віддається перевага над type для публічних API — споживачі можуть їх розширювати. Використовуйте declare module для розширення бібліотек і declare global для розширення глобальної області.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.