classinterfaceimplementsMahir3 mnt baca

implements

Pastikan class memenuhi kontrak interface dengan implements.

Kenapa implements itu ada

extends mewarisi implementasi dari satu parent class. implements beda: ia berkata "class ini WAJIB memenuhi kontrak interface ini", tanpa mewarisi kode apa pun. Ini fondasi pola adapter dan strategy: banyak class boleh punya implementasi yang beda-beda, tapi semuanya dijamin punya bentuk yang sama. Kode yang memakai mereka cukup pegang interface-nya, tidak peduli class konkret apa di baliknya.

Skenario nyata: payment gateway ganda

Sebuah toko online mau mendukung dua payment gateway. Kontraknya cukup satu:

typescript
// src/payment/gateway.ts
export interface PaymentGateway {
  charge(jumlah: number, orderId: string): Promise<string>; // return: transaction id
  refund(transactionId: string): Promise<void>;
}
typescript
// src/payment/stripe-adapter.ts
import type { PaymentGateway } from "./gateway.js";

export class StripeAdapter implements PaymentGateway {
  async charge(jumlah: number, orderId: string): Promise<string> {
    // panggil Stripe API di sini
    return `stripe-tx-${orderId}`;
  }
  async refund(transactionId: string): Promise<void> {
    // panggil Stripe refund di sini
  }
}
typescript
// src/payment/doku-adapter.ts
import type { PaymentGateway } from "./gateway.js";

export class DokuAdapter implements PaymentGateway {
  async charge(jumlah: number, orderId: string): Promise<string> {
    // panggil Doku API di sini
    return `doku-tx-${orderId}`;
  }
  async refund(transactionId: string): Promise<void> {
    // panggil Doku refund di sini
  }
}
typescript
// src/checkout.ts
import type { PaymentGateway } from "./payment/gateway.js";

export async function bayar(
  gateway: PaymentGateway,
  jumlah: number,
  orderId: string
): Promise<string> {
  return gateway.charge(jumlah, orderId);
}

// bayar(new StripeAdapter(), ...) atau bayar(new DokuAdapter(), ...): sama saja.

Fungsi bayar tidak peduli gateway apa yang dipakai. Mau tambah gateway ketiga besok? Buat class baru yang implements PaymentGateway, tidak ada satu baris pun kode lama yang perlu diubah.

Error compiler nyata

Lupa mengimplementasikan satu method:

typescript
export class OvoAdapter implements PaymentGateway {
  async charge(jumlah: number, orderId: string): Promise<string> {
    return `ovo-tx-${orderId}`;
  }
  // refund() ketinggalan!
}
text
error TS2420: Class 'OvoAdapter' incorrectly implements interface 'PaymentGateway'.
  Property 'refund' is missing in type 'OvoAdapter' but required in type 'PaymentGateway'.

Salah tanda tangan method juga langsung ketahuan:

typescript
export class RusakAdapter implements PaymentGateway {
  // charge versi sync, bukan Promise: melanggar kontrak
  charge(jumlah: number, orderId: string): string { return "x"; }
  async refund(transactionId: string): Promise<void> {}
}
text
error TS2416: Property 'charge' in type 'RusakAdapter' is not assignable
  to the same property in base type 'PaymentGateway'.

Compiler berperan sebagai satpam kontrak: tidak ada adapter setengah jadi yang lolos diam-diam ke production.

implements vs extends, jangan tertukar

extendsimplements
Jumlahsatu parent class sajaboleh banyak interface
Mewarisi kodeya, kode parent dipakai ulangtidak, hanya cek bentuk
Dipakai untukhierarki "adalah" (Admin extends User)kontrak "bisa" (bisa di-charge, bisa di-refund)

Satu class boleh extends satu base class SEKALIGUS implements beberapa interface. Itu kombo paling umum di framework: class UserService extends BaseService implements OnModuleInit.

Kapan dipakai di project nyata

  • Adapter pihak ketiga: payment, SMS, email, cloud storage. Interface milikmu, implementasi mengikuti API mereka. Ganti vendor tanpa mengubah business logic.
  • Repository pattern: interface UserRepository dengan PostgresUserRepo untuk production dan InMemoryUserRepo untuk test. Test jadi cepat tanpa butuh database beneran.
  • Plugin dan strategy: sistem diskon (DiskonPersen implements StrategiDiskon, DiskonNominal implements StrategiDiskon), exporter laporan (PDF, Excel), notifier (WhatsApp, email). Tambah varian baru tanpa menyentuh kode lama.

Catatan teknis: implements hanya dicek saat compile dan hilang total saat runtime. Jadi jangan pakai instanceof PaymentGateway untuk pengecekan, karena interface tidak punya wujud di JavaScript hasil compile. Kalau butuh cek runtime, pakai class konkretnya (x instanceof StripeAdapter) atau type guard manual.

Tantangan

Kontrak penyimpanan

Buat interface Penyimpanan dengan simpan(kunci: string, nilai: string): void dan ambil(kunci: string): string | undefined. Lalu class Memori implements Penyimpanan memakai Map di dalamnya. Test simpan dan ambil.

typescript
interface Penyimpanan {
  simpan(kunci: string, nilai: string): void;
  ambil(kunci: string): string | undefined;
}

class Memori implements Penyimpanan {
  private data = new Map<string, string>();
  // lengkapi kedua method
}

const m = new Memori();
m.simpan("nama", "Budi");
console.log(m.ambil("nama")); // "Budi"