JavaScript >> Javascript 文檔 >  >> Node.js

我如何理解打字稿中的協變和逆變

協變、逆變、雙變……這些詞對你來說似乎陌生,難以理解?

我向你保證,在本文的最後,所有這些都會讓你更清楚。

什麼是?

當您使用類時,一個類可以擴展到另一個類。例如:

class Animal {}

class Dog extends Animal {}

class Greyhound extends Dog {}

這意味著兩件重要的事情:

  • 是一個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 行為,但為什麼呢?

好的好的,我們將說明這個unsound 案子 !

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 是 unsound ,但不要難過我們可以解決這個問題,感謝 Typescript 2.6 你只需要使用 --strictFunctionTypes 在你的 Ts 配置中標記。

所以 makeAnimalAction 需要是 contravariant 對於參數類型。多虧了這一點,我們可以避免對 Cat 進行 Dog 動作!

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中函數的返回類型是covariant

感謝您閱讀此內容.....好吧,我將嘗試演示它!

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 或一個 subtype makeDogBark 的返回類型中的 Dog 爭論。所以返回的類型需要是 covariant

TL;TR &結論

所以在 Typescript 中,參數類型需要是 contravariant 並且函數類型需要是 covariant 在他們的返回類型中。

我希望你喜歡這篇文章!

🎁你可以得到我的新書Underrated skills in javascript, make the difference 如果你在 Twitter 上關注我並 MP 我 😁

或者在這裡獲取

🎁 我的時事通訊

☕️你可以支持我的作品🙏

🏃‍♂️你可以關注我👇

🕊 推特:https://twitter.com/code__oz

👨‍💻 Github:https://github.com/Code-Oz

並且你可以標記🔖這篇文章!

我使用 https://www.stephanboyer.com/post/132/what-are-covariance-and-contravariance 來理解和解釋這篇文章


Tutorial JavaScript 教程
  1. 使用 RingCentral Webhook

  2. 為什麼第一行不是函數? [關閉]

  3. 使用 Rave 和 Vue 創建基本的在線支付流程

  4. 如何在 React Native 中創建自定義的完全響應式文本組件

  5. iPad Safari 觸摸事件

  6. Vue-Nuxt 為 SEO 從渲染文本中刪除 html 標籤

  7. 讓, var 或 const ?

  1. 帶參數的控制台日誌

  2. 圖片滑塊 {day -26}

  3. 如何使用 Nx 輕鬆創建與 ES/AMD/UMD/CJS 模塊系統兼容的 JS 庫

  4. 如何從表中獲取數據?

  5. JavaScript 中的 THIS 關鍵字是什麼? - 第1部分

  6. 在 JavaScript 中解構 this 對象

  7. JavaScript 事件循環和調用堆棧解釋

  1. 用 A 型框架建造紙板地牢

  2. 使用 D3 和 Svelte 的地圖

  3. 深入 Dojo:DOM 基礎

  4. ng-容器