structural typing в інтерфейсах
1. Що таке structural typing (структурна типізація)
Structural typing - це принцип, за яким сумісність типів визначається за їхньою формою (структурою), а не за іменем типу.
Простіше кажучи:
якщо об'єкт виглядає як інтерфейс, TypeScript вважає, що він відповідає цьому інтерфейсу.
Приклад
interface User {
id: number;
name: string;
}
const person = {
id: 1,
name: "Tim",
age: 25,
};
// Можна присвоїти - структура збігається
const u: User = person;Хоча
personне оголошений якUser, TypeScript бачить, що в нього є всі потрібні поля (idіname), і вважає типи сумісними.Зайві поля (
age) не заважають.
2. На відміну від номінальної типізації (nominal typing)
У деяких мовах (наприклад, Java, C#, Swift) сумісність типів перевіряється за іменем або за декларацією, а не за структурою.
Приклад (як було б за nominal typing):
class User { int id; String name; }
class Person { int id; String name; }
// Помилка - типи різні, хоча поля однакові
User u = new Person();У TypeScript навпаки - головне, щоб структура збігалася. І це робить мову гнучкішою та "утилітарнішою".
3. Як TypeScript перевіряє сумісність структур
TypeScript порівнює форму об'єктів, а не їхнє "походження".
Приклад:
interface Point {
x: number;
y: number;
}
const coord = { x: 10, y: 20, z: 30 };
const p: Point = coord; // OKПеревіряється: "Чи є в
coordвластивостіxтаyпотрібних типів?" - Так -> отже, він відповідаєPoint.
4. Структурна типізація працює і з функціями
interface Logger {
(msg: string): void;
}
function logToConsole(message: string) {
console.log(message);
}
const logger: Logger = logToConsole; // OKTypeScript перевіряє сигнатуру функції, а не те, як вона названа.
5. Чому це важливо
Завдяки структурній типізації:
- можна використовувати інлайн-об'єкти без явних інтерфейсів;
- типи стають гнучкими та сумісними;
- легко працювати із зовнішніми даними (API, JSON);
- зменшується кількість "церемоній" (менше boilerplate-коду).
Приклад: "качина типізація" (duck typing)
"Якщо щось крякає як качка і виглядає як качка, TypeScript вважає, що це качка."
interface Duck {
quack(): void;
}
const animal = {
quack: () => console.log("Quack!"),
};
const d: Duck = animal; // OK - структура збігається6. Як structural typing впливає на інтерфейси
Інтерфейси в TypeScript:
- не є реальними сутностями під час виконання;
- визначають лише форму даних;
- працюють за принципом структурної відповідності.
Приклад:
interface Car {
wheels: number;
}
interface Truck {
wheels: number;
}
let c: Car = { wheels: 4 };
let t: Truck = c; // OK - структура збігаєтьсяХоча
CarіTruck- різні інтерфейси, TypeScript вважає їх сумісними, тому що вони мають однакову структуру.
7. Коли це може бути неочікуваним
Іноді структурна типізація призводить до "надто гнучкої" поведінки:
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
const point3D: Point3D = { x: 1, y: 2, z: 3 };
const p2d: Point2D = point3D; // OKTypeScript не проти - адже в
point3Dє все, що потрібноPoint2D. Але це може призвести до логічних помилок, якщо ти очікував 2D-точку.
8. Structural typing і класи
Класи теж структурно типізовані. Тобто неважливо, "від чого" вони успадковуються - важливо, що в них є.
class Person {
name = "Tim";
}
interface Named {
name: string;
}
let p: Named = new Person(); // OK - поля збігаютьсяНавіть якщо
Personне "реалізує" інтерфейсNamed, він все одно сумісний з ним.
Підсумок
Structural typing - це спосіб перевірки типів у TypeScript, за якого сумісність визначається за структурою, а не за іменем.
Тобто: якщо об'єкт містить усі необхідні властивості потрібних типів, він вважається сумісним з інтерфейсом.
Переваги:
- гнучкість і зручність при роботі з даними;
- менше коду (не потрібно явно "implements" все підряд);
- ідеально підходить для JSON, API, функцій та об'єктів.
Мінус:
- можна випадково передати "зайві" дані і не помітити невідповідності логіки.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.