# Covariance dan Contravariance

Sebagai developer sangat penting untuk bisa memahami konsep **Covariance dan Contravariance** pada konsep Polymorphism dan inheritance/turunan. Karena pada konsep ini terdapat aturan-aturan yang harus diikuti ketika diperlukan kemanan dari tipe-tipe return atau argument.

Coba perhatikan gambar di bawah ini.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1739802263616/45fcc509-26a4-476b-b0c5-b4f799d37d5e.png align="center")

Gambar 1 diambil dari [Wiki](https://en.wikipedia.org/wiki/Covariance_and_contravariance_\(computer_science\))

## Invariant ( Kiri )

Pada *gambar 1* terlihat pada sisi **Kiri.** Aturan yang harus dipatuhi pada subtype-nya (ClassB) tidak ada perubahan signature method baik Nilai argument atau nilai return dari method. Jadi masih mengikuti supertype-nya. Tapi mungkin ada perbedaan pada detail-detail logic method lainnya dengan syarat semua property dan methodnya selalu bernilai valid sesuai asumsi yang sudah dirancang. Untuk pembahasan lebih detail bisa melihat tulisan pada link [berikut ini.](https://hashnode.com/post/cmasacigd000d09jv9w6tdbxf)

```typescript
class KetuaKelas {
    async order(): Promise<OrderResponse> {
        const result = await this.executeOrder()
        return result as OrderResponse
    }

    async executeOrder() {
       // Execute 
    }
}

class WakilKetua extends KetuaKelas {
   async order(): Promise<OrderResponse> {
      const granted = await this.askPermissionKetua()
      if (!granted) {
           throw new Error("Unapproved")
      }

      const result = await this.executeOrder()
      return result as OrderResponse
   }

   async executeOrder() {
       // Execute 
   }

   async askPermissionKetua() {
      return true
   }
}
```

Pada code terdapat dua class yaitu `KetuaKelas` dan `WakilKetua` dimana `KetuaKelas` merupakan **Supertype** dan `WakilKetua` adalah **Subtype** terlihat dari extends keyword pada class `WakilKetua`.

Pada class `KetuaKelas` terdapat method dengan nama `order` dan juga `executeOrder`. Dimana method ini juga digunakan pada class `WakilKetua`. Juga baik di class `KetuaKelas` dan juga `WakilKetua` tidak ada perubahan argument maupun return method. Inilah yang disebut **Invariant**. Method di **Subtype** tidak merubah signature dari method di **Supertype**\-nya.

## Covariance ( Tengah )

Pada gambar 1 bagian **Tengah** disebut covariance, karena return type pada subtype tidak memiliki nilai yang lebih general atau lebih luas dari pada supertype nya. Aturan ini digunakan untuk menjaga output type pada suatu process. Sebagai contoh

```typescript
let keranjang: Buah[] = []

class Jambu implement Buah {}

let obj = Jambu
```

Pada contoh code tersebut, `let keranjang` dengan tipe data array dimana isinya adalah kumpulan buah, oleh karena itu pendefinisian pada variable ini adalah `Buah[]`. `Buah` disini adalah supertypenya. Ketika `obj` dari `Jambu` akan dimasukan ke dalam `kerajang`. Dimana `Jambu` adalah bagian dari `Buah`, maka `Jambu` boleh dimasukan ke dalam `Keranjang`. Karena `Jambu` bagian dari `Buah` maka Jambu merupakan subtype dari `Buah`.

Lalu bagaimana dalam turunan/inheritance? sebagai contoh terdapat code seperti ini

```typescript
type Buah = {
   berbiji: boolean
}
type Jeruk = Buah & { berbiji: boolean }

class Keranjang {
  sudahMatang(): Buah {}
}

class Bungkus extends Keranjang {
   sudahMatang(): Jeruk {}
}
```

Pada code tersebut terdapat dua type yaitu `Buah` dan `Jeruk` dimana `Buah` digunakan sebagai *return type method* `sudahMatang` pada class `Keranjang`, sedangkan `Jeruk` digunakan sebagai *return type method* `sudahMatang` pada class `Bungkus`. Dimana `Bungkus` adalah turunan dari `Keranjang`.

Seperti yang kita lihat pada code bahwa pada class `Bungkus` memiliki method yang sama dengan \*parent class-nya, yaitu `sudahMatang`. Tapi yang membedakan adalah *return type* pada masing-masing class.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1739932842216/a8af62db-c4d6-4a09-a017-2a6358c12984.png align="center")

Terlihat bahwa *return method* pada class `Bungkus` memiliki nilai lebih spesifik (T’) dari pada *return type* *method* (T) pada parent classnya yaitu `Keranjang`. Maka dari itu dilihat dari arah panah *inheritance* dan juga *degree* dari return type searah. Sehingga disebut *covariance* dengan tujuannya adalah untuk mengamankan *return type.*

## Contravariance (Kanan)

Sisi **Kanan** pada *gambar 1*\*\*,\*\* disebut *Contravariance*, dimana nilai Argument yang diikutkan dalam method dari *subtype* (T) memiliki nilai lebih general atau luas dari pada *supertype*\-nya (T’), disebut sebagai Contravariance. Aturan ini digunakan untuk menjaga type dari argument yang di-*override* oleh subtypenya.

Sebagai contoh kita bisa lihat code berikut

```typescript
type Buah = {
   berbiji: boolean
}
type Jeruk = Buah & { berbiji: boolean }

class Keranjang {
  sudahMatang(item: Jeruk){} 
}

class Bungkus extends Keranjang {
   sudahMatang(item: Buah) {}
}
```

Code tersebut mirip dengan code sebelumnya pada bagian pembahasan *Covariance*. Perbedaannya adalah *Convariance* mengatur return type sedangkan *Contravariance* mengatur Argument. Selain itu, pada covariance nilai yang lebih general ada pada Supertype-nya, sedangkan pada *Contravariance* sebaliknya. Nilai yang lebih general ada pada *subtype*\-nya. Oleh karena itu arah panahnya berlawanan.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1739933023811/9b8830f0-632d-4c01-a859-29b5f27a8cef.png align="center")

### Kesimpulan

Ketika membuat code, kita tidak selalu perlu mengimplentasikan Covariance atau Contravariance. Kita memerlukannya hanya pada saat memang diperlukan pengamanan pada tipe data kembalian method atau parameter. Agar integritas nilai yang masuk maupun keluar cukup terjaga.
