Type Compatibility

Type Compatibility

Сумісність типу (як ми обговорюємо тут) визначає, чи можна призначити один предмет іншому. наприклад string i number несумісні:

let str: string = "Hello";
let num: number = 123;

str = num; // ERROR: `number` is not assignable to `string`
num = str; // ERROR: `string` is not assignable to `number`

Soundness

Система типів TypeScript розроблена так, щоб бути зручною та допускати unsound поведінку, напр. будь-що можна призначити будь-якому, що означає, що компілятор повинен дозволити вам робити все, що завгодно:

Structural

Об'єкти TypeScript є структурно типізованими. Це означає, що іменуванняs не мають значення, якщо структури збігаються

Це дозволяє вам створювати об’єкти на льоту (як ви це робите у vanilla JS) і залишатися в безпеці, коли це можна зробити.

Також більше даних вважається правильним

Variance

Дисперсія — це легке для розуміння та важливе поняття для аналізу сумісності типів.

Для простих типів Base і Child, якщо Child є дочірнім типом Base, тоді екземпляри Child можна призначити змінній типу Base.

Це поліморфізм 101

Сумісність типів складних типів, що складаються з таких типів Base і Child, залежить від того, де Base і Child у подібних сценаріях керуються variance.

  • Коваріант: (співпраця, він же спільний) тільки в спільному напрямку

  • Контраваріант: (контра, він же негативний) тільки вoпротилежний напрямок

  • Біваріант : (bi або обидва) і co, і contra.

  • Invariant : якщо типи не зовсім однакові, вони несумісні.*

Примітка: для повністю надійної системи за наявності змінних даних, таких як JavaScript, invariant є єдиним дійсним варіантом. Але, як уже згадувалося, зручність змушує нас робити необґрунтований вибір.

Functions

Порівнюючи дві функції, слід враховувати кілька тонких моментів.

Return Type

covariant: тип повернення має містити принаймні достатньо даних.

Number of arguments

Менша кількість аргументів — це добре (тобто функції можуть ігнорувати додаткові параметри). Адже вам гарантовано викличете їх із як мінімум достатніми аргументами.

Optional and Rest Parameters

Необов’язкові (попередньо визначена кількість) і параметри Rest (будь-яка кількість аргументів) сумісні, знову ж для зручності.

Примітка: необов’язковий (у нашому прикладі bar) і необов’язковий (у нашому прикладі foo) сумісні, лише якщо strictNullChecks має значення false.

Types of arguments

bivariant : це розроблено для підтримки типових сценаріїв обробки подій

Крім того, Array<Child> можна призначити Array<Base> (коваріація), оскільки функції сумісні. Коваріація масиву вимагає, щоб усі функції Array<Child> можна було призначити Array<Base>, наприклад. push(t:Child) можна призначити push(t:Base), що стало можливим завдяки біваріантності аргументів функції.

Це може збити з пантелику людей, які знають інші мови, які очікували б наступного помилки, але не в TypeScript:

Enums

  • Enum сумісні з числами, а числа сумісні з enum.

** Значення Enum з різних типів enum вважаються несумісними. Це робить переліки придатними для використання номінально (на відміну від структурних)

Classes

  • Порівнюються лише члени екземпляра та методи.constructors і statics не грають ролі.

  • private та protected члени повинні походити з того самого класу. Такі члени по суті роблять клас nominal.

Generics

Оскільки TypeScript має структурну систему типів, параметри типу впливають на сумісність лише тоді, коли вони використовуються членом. Наприклад, у наступному T не впливає на сумісність:

Однак, якщо використовується T, він відіграватиме роль у сумісності на основі свого екземпляру, як показано нижче:

У випадках, коли загальні аргументи не були інстанцировані, вони замінюються на any перед перевіркою сумісності:

Універсали, що включають класи, відповідають відповідній сумісності класів, як згадувалося раніше

FootNote: Invariance

Ми сказали, що інваріантність — це єдиний правильний варіант. Ось приклад, коли дисперсія contra і co небезпечна для масивів.

Last updated