Skip to main content
Практика завдань

Структурна типізація (утка типізація) в TypeScript

Що таке структурна типізація?

TypeScript використовує структурну типізацію — типи сумісні на основі їх структури (форми/властивості), а не їх імені або оголошення. Якщо два типи мають однакову структуру, вони сумісні.

"Якщо воно йде, як качка, і крякає, як качка, то це, напевно, качка."


Основний приклад

typescript
interface Point { x: number; y: number; } // Не потрібне явне "implements Point"! const point = { x: 10, y: 20, z: 30 }; function printPoint(p: Point): void { console.log(`(${p.x}, ${p.y})`); } printPoint(point); // ✅ Працює! point має x та y

Структурна vs Номінальна типізація

Структурна (TypeScript)Номінальна (Java, C#)
Типи співпадають за структуроюТипи співпадають за іменем/оголошенням
Не потрібно implementsПотрібно явно реалізувати інтерфейс
Більш гнучкаБільш сувора
typescript
// У TypeScript (структурна): interface Cat { meow(): void } interface CatLike { meow(): void } const cat: Cat = { meow() {} }; const catLike: CatLike = cat; // ✅ Однакова структура = сумісні // У Java (номінальна): це б не вдалося // Cat і CatLike — це різні типи, навіть з однаковими методами

Перевірка надмірних властивостей

TypeScript має спеціальну сувору перевірку для літералів об'єктів (пряме присвоєння):

typescript
interface Config { host: string; port: number; } // ❌ Перевірка надмірних властивостей — літерал об'єкта const config: Config = { host: "localhost", port: 3000, debug: true // ❌ Помилка: 'debug' не існує в типі 'Config' }; // ✅ Немає перевірки надмірних властивостей — через змінну const obj = { host: "localhost", port: 3000, debug: true }; const config: Config = obj; // ✅ Працює (структурна сумісність) // ✅ Немає перевірки надмірних властивостей — через аргумент функції function startServer(config: Config) {} startServer(obj); // ✅ Працює

Сумісність класів

typescript
class Animal { name: string; constructor(name: string) { this.name = name; } } class Person { name: string; constructor(name: string) { this.name = name; } } // Структурно сумісні — однакова форма! let animal: Animal = new Person("Alice"); // ✅ let person: Person = new Animal("Dog"); // ✅

Коли структурна типізація викликає проблеми

typescript
type USD = number; type EUR = number; // ❌ Немає безпеки типів — обидва це просто числа function convertToEUR(amount: USD): EUR { return amount * 0.85; } const euros: EUR = 100; convertToEUR(euros); // ✅ Немає помилки! (але логічно неправильно)

Рішення: Брендовані типи

typescript
type USD = number & { __brand: "USD" }; type EUR = number & { __brand: "EUR" }; function usd(amount: number): USD { return amount as USD; } function convertToEUR(amount: USD): EUR { return (amount * 0.85) as EUR; } const dollars = usd(100); convertToEUR(dollars); // ✅ convertToEUR(100 as EUR); // ❌ Помилка: EUR не можна присвоїти USD

Важливо:

Структурна типізація робить TypeScript гнучким і сумісним з патернами JavaScript. Однак це означає, що типи з однаковою формою є взаємозамінними — використовуйте брендовані типи, коли вам потрібна поведінка, подібна до номінальної (наприклад, валюта, ідентифікатори користувачів тощо).

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань