Как разбирам ковариацията и контравариацията в машинопис
Ковариантност, контравариантност, бивариантност... Тези думи изглеждат непознати, трудни за разбиране за вас?
Обещавам ви, че в края на тази статия всичко това ще бъде по-ясно за вас.
Какво е?
Когато използвате клас, един клас може да се разшири към друг клас. Например:
class Animal {} class Dog extends Animal {} class Greyhound extends Dog {}
Това означава 2 важни неща:
- Куче е subtype
от Животно, а Животное supertype
от Куче.
- Кучее supertype
от Хрътка, а Хрътка е subtype
от Куче.
Да, хубаво и ?
Вече можем да разберем дефинициите за ковариация, контравариантност и бивариантност!
Ковариация:
Ковариация приема subtype
но не приема supertype
Можем да вземем функция, която приема само covariant
тип от Dog
const acceptDogCovariance = function (value: Covariant<Dog>) { … } acceptDogCovariance(new Animal()) // Error, since Animal is a supertype of Dog acceptDogCovariance(new Dog()) // Ok acceptDogCovariance(new Greyhound()) // Ok since Greyhound is a subtype of Dog
Контравариантност:
Контравариантността приема supertype
но не приема subtype
const acceptDogContravariance = function (value: Contravariance<Dog>) { … } acceptDogContravariance(new Animal()) // Ok, since Animal is a supertype of Dog acceptDogContravariance(new Dog()) // Ok acceptDogContravariance(new Greyhound()) // Error since Greyhound is a subtype of Dog
двувариантност:
Бивариантността приема и двете, supertype
и subtype
!
Така че сега научаваме дефинициите, но как работи в Typescript? Специално за function
Как Typescript използва ковариация и контравариация за аргумент във функция?
Легитен въпрос, нали?
В машинопис типовете аргументи са bivariant
! Всъщност това не е correct
поведение, но защо?
Добре, добре, ще илюстрираме този нездрав случай!
class Animal { doAnimalThing(): void { console.log(“I am a Animal!”) } } class Dog extends Animal { doDogThing(): void { console.log(“I am a Dog!”) } } class Cat extends Animal { doCatThing(): void { console.log(“I am a Cat!”) } } function makeAnimalAction(animalAction: (animal: Animal) => void) : void { let cat: Cat = new Cat() animalAction(cat) } function dogAction(dog: Dog) { dog.doDogThing() } makeAnimalAction(dogAction) // TS Error at compilation, since we are trying to use doDogThing() to a Cat
В един пример можем да демонстрираме, че Bivariance за типа на аргумента е неправилен, но не тъгувайте, можем да поправим това благодарение на Typescript 2.6, просто трябва да използвате— strictFunctionTypes флаг във вашата Ts конфигурация.
Така че makeAnimalAction трябва да бъде контравариантен за тип аргумент. Благодарение на това можем да избегнем да правим куче действие на котка!
function makeAnimalAction(animalAction: (animal: Animal) => void) : void { let cat: Cat = new Cat() animalAction(cat) } function animalAction(animal: Animal) { animal.doAnimalThing() } makeAnimalAction(animalAction) // “I am a Animal!”
Как Typescript използва ковариация и контравариация за върнат тип във функция?
Върнатият тип на функция в Typescript е ковариантен!
Благодаря ви, че прочетохте това….. Добре, добре, ще се опитам да го демонстрирам!
class Animal {} class Dog extends Animal { bark(): void { console.log(“Bark”) } } class Greyhound extends Dog {} function makeDogBark(animalAction: (animal: Animal) => Dog) : void { animalAction(new Animal()).bark() } function animalAction(animal: Animal): Animal { return animal } makeDogBark(animalAction) // Error since not all Animal can bark.
Тук трябва да имаме Dog или подтип на Dog във върнат тип за аргумента makeDogBark. Така че върнатият тип трябва да бъде ковариантен.
TL;TR & Заключение
Така че в Typescript типовете аргументи трябва да бъдат контравариантни, а функционалните типове трябва да бъдат ковариантни в техните връщани типове.
Надявам се това четиво да ви хареса!
🎁 Можете да получите моята нова книга Недооценени умения в javascript, направете разликата БЕЗПЛАТНО, ако ме последвате в Twitter и ме запишете 😁
Или го вземете ТУК
☕️ Можете да ПОДКРЕПИТЕ МОИТЕ РАБОТИ 🙏
🏃♂️ Можете да ме последвате на 👇
🕊 Туитър
👨💻 Github
И можете да маркирате 🔖 тази статия!
Използвам https://www.stephanboyer.com/post/132/what-are-covariance-and-contravariance, за да разбера и обясня тази статия