Как я понимаю ковариацию и контравариантность машинописного текста
Ковариация, контравариантность, двойственность… Эти слова кажутся вам незнакомыми, трудными для понимания?
Обещаю, что в конце статьи все это станет для вас более наглядным.
Что?
Когда вы используете класс, он может расширяться до другого класса. Например:
class Animal {} class Dog extends Animal {} class Greyhound extends Dog {}
Это означает 2 важные вещи:
- Собака - это subtype
из Животного, а Животное - это supertype
из Собаки.
- Собака - это supertype
из борзой, а борзой - subtype
из собаки.
Да приятно и?
Теперь мы можем понять определения ковариантности, контравариантности и бивариантности!
Ковариация:
Ковариация принимает subtype
но не принимает supertype
Мы можем взять функцию, которая будет принимать только covariant
type 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
В одном примере мы можем продемонстрировать, что двухвариантность для типа аргумента несостоятельна, но не расстраивайтесь, мы можем исправить это благодаря Typescript 2.6, вам просто нужно использовать - strictFunctionTypes флаг в вашем Ts config.
Поэтому 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 и поделитесь со мной MP 😁
Или получите ЗДЕСЬ
🎁 МОЙ ИНФОРМАЦИОННЫЙ БЮЛЛЕТЕНЬ
☕️ Вы можете ПОДДЕРЖАТЬ МОИ РАБОТЫ 🙏
🏃♂️ Ты можешь подписаться на меня на 👇
👨💻 Github
И вы можете отметить 🔖 эту статью!
Я использую https://www.stephanboyer.com/post/132/what-are-covariance-and-contravariance, чтобы понять и объяснить эту статью