Как я понимаю ковариацию и контравариантность машинописного текста

Ковариация, контравариантность, двойственность… Эти слова кажутся вам незнакомыми, трудными для понимания?

Обещаю, что в конце статьи все это станет для вас более наглядным.

Что?

Когда вы используете класс, он может расширяться до другого класса. Например:

class Animal {}
class Dog extends Animal {}
class Greyhound extends Dog {}

Это означает 2 важные вещи:

- Собака - это subtype из Животного, а Животное - это supertype из Собаки.

- Собака - это supertypeиз борзой, а борзой - subtypeиз собаки.

Да приятно и?

Теперь мы можем понять определения ковариантности, контравариантности и бивариантности!

Ковариация:

Ковариация принимает subtype но не принимает supertype

Мы можем взять функцию, которая будет принимать только covarianttype 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 😁

Или получите ЗДЕСЬ

🎁 МОЙ ИНФОРМАЦИОННЫЙ БЮЛЛЕТЕНЬ

☕️ Вы можете ПОДДЕРЖАТЬ МОИ РАБОТЫ 🙏

🏃‍♂️ Ты можешь подписаться на меня на 👇

🕊 Twitter

👨‍💻 Github

И вы можете отметить 🔖 эту статью!

Я использую https://www.stephanboyer.com/post/132/what-are-covariance-and-contravariance, чтобы понять и объяснить эту статью