Antarmuka TypeScript vs Tipe: Perbedaan Nyata, Diuji Dengan Kompiler
Antarmuka dan alias tipe saling tumpang tindih sehingga pilihannya sering kali terasa sewenang-wenang. Inilah yang masing-masing dapat lakukan namun tidak dapat dilakukan oleh yang lain, yang dikonfirmasi oleh kesalahan kompiler nyata, ditambah aturan sederhana yang dapat diikuti oleh tim Anda.
- Untuk bentuk objek biasa, antarmuka dan tipe alias hampir dapat dipertukarkan.
- Hanya
typeyang dapat memberi nama gabungan, tupel, dan tipe non-objek lainnya. - Hanya
interfaceyang mendukung penggabungan deklarasi, yang mana dua deklarasi digabungkan. - Aturan umum: antarmuka untuk bentuk objek,
typeuntuk yang lainnya, diterapkan secara konsisten.
Beberapa pertanyaan TypeScript menimbulkan perdebatan sebanyak antarmuka TypeScript vs tipe. Banyak artikel mencantumkan perbedaan yang dulunya penting di versi lama tetapi sekarang sudah ketinggalan zaman. Jadi, daripada mengulangi klaim, kami mengujinya.
Kami menulis satu file untuk menguji setiap perbedaan, dan memeriksanya dengan TypeScript 5.6.3 dalam mode ketat. Kesalahan kompiler yang dikutip di bawah ini berasal dari proses tersebut. Perilaku dapat berubah antar versi, jadi periksalah versi TypeScript yang digunakan proyek Anda. Jika Anda baru mengenal bahasa ini, mulailah dengan Tutorial TypeScript untuk pemula kami.
Jawaban singkatnya
interface mendeskripsikan bentuk suatu objek, dan dapat diperluas atau dibuka kembali. Alias type memberi nama pada tipe apa saja, termasuk objek, gabungan, tupel, dan tipe fungsi. Jika keduanya bisa berfungsi, perbedaannya sebagian besar terletak pada gaya.
Dimana mereka sama
Kedua deklarasi ini mendeskripsikan bentuk yang identik:
interface User {
id: number;
name: string;
email?: string;
}
type UserAlias = {
id: number;
name: string;
email?: string;
};
const a: User = { id: 1, name: "Asha" };
const b: UserAlias = a; // no error
TypeScript menggunakan pengetikan struktural, yang berarti membandingkan bentuk, bukan nama. Itu sebabnya User dapat ditugaskan ke UserAlias tanpa keluhan. Keduanya mendukung properti opsional, properti readonly, metode, dan tanda tangan indeks.
Antarmuka vs tipe berdampingan
| Fitur | antarmuka | mengetik |
|---|---|---|
| Bentuk objek | Ya | Ya |
Serikat pekerja, seperti "a" | "b" |
Tidak | Ya |
| Tupel dan primitif | Tidak | Ya |
| Tipe yang dipetakan dan bersyarat | Tidak | Ya |
| Penggabungan deklarasi | Ya | Tidak, ini adalah kesalahan |
| Memperluas | meluas |
& persimpangan |
| Sifat-sifat yang bertentangan | Kesalahan pada deklarasi | Diam-diam bisa menjadi never |
Digunakan dengan implements |
Ya | Ya, jika itu adalah tipe objek |
Apa yang hanya bisa dilakukan oleh tipe
Banyak tipe berguna yang bukan merupakan bentuk objek sama sekali, dan hanya alias tipe yang dapat menamainya:
type Status = "pending" | "paid" | "shipped"; // union
type Point = [number, number]; // tuple
type Handler = (event: string) => void; // function type
type Keys = keyof User; // computed type
type ReadonlyUser = Readonly<User>; // utility type
Tipe gabungan adalah salah satu fitur TypeScript yang paling berharga, karena kompiler kemudian menolak nilai apa pun di luar daftar:
let s: Status = "paid";
s = "refunded";
// error TS2322: Type '"refunded"' is not assignable to type 'Status'.
Ini menangkap kesalahan ketik dan nilai-nilai usang pada waktu kompilasi, sebelum mencapai produksi.
Penggabungan deklarasi
Jika Anda mendeklarasikan antarmuka dengan nama yang sama dua kali, TypeScript menggabungkannya menjadi satu:
interface Settings {
theme: string;
}
interface Settings {
language: string;
}
const settings: Settings = { theme: "dark", language: "en" }; // no error
Coba hal yang sama dengan alias tipe, dan kompiler menolak:
type Config = { theme: string };
type Config = { language: string };
// error TS2300: Duplicate identifier 'Config'.
Penggabungan adalah cara perpustakaan memungkinkan Anda memperluas tipenya. Misalnya, Anda dapat menambahkan properti khusus ke antarmuka global Window, atau ke objek permintaan kerangka kerja, tanpa mengubah pustaka. Itu sungguh berguna.
Sisi sebaliknya adalah penggabungan bisa terjadi secara tidak sengaja. Jika dua file dalam sebuah proyek mendeklarasikan antarmuka dengan nama yang sama dalam cakupan yang sama, keduanya digabungkan secara diam-diam, yang dapat membingungkan. Alias tipe membuat tabrakan itu menjadi kesalahan.
memanjang vs persimpangan
Keduanya memungkinkan Anda membangun tipe yang sudah ada:
interface Admin extends User {
permissions: string[];
}
type AdminAlias = UserAlias & { permissions: string[] };
Untuk properti yang kompatibel, hasilnya sama. Perbedaannya muncul dengan konflik. Ketika sebuah antarmuka mencoba mengubah tipe properti secara tidak kompatibel, kompilator segera melaporkannya:
interface Base { id: number }
interface Broken extends Base { id: string }
// error TS2430: Interface 'Broken' incorrectly extends interface 'Base'.
// Types of property 'id' are incompatible.
// Type 'string' is not assignable to type 'number'.
Sebuah persimpangan tidak mengeluh ketika diumumkan. Sebaliknya, properti yang bertentangan menjadi never, sebuah tipe yang tidak memiliki nilai apa pun. Kesalahan hanya muncul kemudian, ketika Anda mencoba menggunakannya:
type Mixed = { id: number } & { id: string };
const m: Mixed = { id: 1 };
// error TS2322: Type 'number' is not assignable to type 'never'.
Kesalahan berikutnya lebih membingungkan karena menunjukkan kesalahan yang sebenarnya. Ini adalah salah satu alasan praktis untuk memilih extends ketika membangun tipe objek.
Kelas dan implementasinya
Sebuah kelas bisa berjanji untuk mencocokkan bentuk menggunakan implements, dan ini berfungsi dengan antarmuka atau alias tipe objek:
class Account implements User {
constructor(public id: number, public name: string) {}
}
Ini dikompilasi tanpa kesalahan. Perhatikan bahwa implements hanya memeriksa apakah kelasnya cocok. Itu tidak menambahkan properti atau kode apa pun. Sebuah kelas tidak dapat mengimplementasikan tipe gabungan, karena tidak ada satu bentuk pun yang cocok.
Tipe readonly dan utilitas
Jenis utilitas seperti Readonly, Partial, Pick dan Omit berfungsi dengan antarmuka dan alias. Hasilnya adalah tipe baru, yang biasanya diberi nama dengan alias tipe:
const r: ReadonlyUser = { id: 3, name: "Dev" };
r.name = "Chitra";
// error TS2540: Cannot assign to 'name' because it is a read-only property.
Ingatlah bahwa readonly hanya merupakan pemeriksaan waktu kompilasi. Saat dijalankan, objeknya adalah JavaScript biasa, dan masih dapat diubah dengan kode yang melewati tipe tersebut.
Kiat: Tipe menghilang saat TypeScript dikompilasi ke JavaScript. Data yang datang dari luar, seperti respons API, tidak diperiksa pada saat dijalankan hanya karena memiliki tipe. Validasi, misalnya dengan perpustakaan skema. Tutorial Pengambilan API kami mencakup penanganan respons API dengan aman.
Kinerja kompiler
Panduan kinerja tim TypeScript sendiri menyarankan untuk memilih antarmuka yang menggunakan extends daripada persimpangan besar, karena kompiler dapat menyimpan hubungan antarmuka dalam cache dengan lebih efisien. Dalam proyek kecil dan menengah, Anda tidak akan melihat perbedaan apa pun. Ini mungkin penting dalam basis kode yang sangat besar dengan tipe yang sangat tersusun. Kami tidak mengukurnya sendiri.
Mana yang harus Anda gunakan?
Aturan yang banyak digunakan, sejalan dengan panduan dari buku pegangan TypeScript, adalah:
- Gunakan
interfaceuntuk bentuk objek, terutama API publik dan apa pun yang diimplementasikan oleh kelas atau yang lain dapat diperluas. - Gunakan
typeuntuk gabungan, tupel, tipe fungsi, dan tipe yang dipetakan atau dihitung.
| Anda mendefinisikan | Gunakan |
|---|---|
| Model data, seperti Pengguna atau Pesanan | antarmuka |
| Satu set nilai yang diizinkan | type persatuan |
| Sepasang atau tripel dengan panjang tetap | type tupel |
| Tanda tangan panggilan balik | mengetik |
| Memperluas tipe perpustakaan | interface, melalui penggabungan |
| Variasi dari tipe yang sudah ada | type dengan tipe utilitas |
Beberapa tim cukup menggunakan type di mana saja, dan itu juga berfungsi dengan baik. Yang paling penting adalah konsistensi, jadi pilihlah konvensi, tuliskan dalam panduan gaya Anda dan biarkan linter menerapkannya. Aturan ESLint consistent-type-definitions dari TypeScript-eslint dapat melakukan ini.
Kesalahan umum
- Perdebatan tanpa akhir. Keduanya baik-baik saja untuk objek, jadi selesaikan aturannya sekali dan lanjutkan.
- Penggabungan yang tidak disengaja. Menggunakan kembali nama antarmuka dalam cakupan yang sama menggabungkannya secara diam-diam.
- Persimpangan yang bertentangan. Mereka membuat tipe
neverdengan kesalahan yang membingungkan nantinya. - Jenis yang dipercaya pada waktu proses. Tipe tersebut akan terhapus, jadi validasi data eksternal.
- Menggunakan
anyuntuk membungkam kesalahan. Ini mematikan pemeriksaan. Pilihunknowndan persempit.
Beralih di antara keduanya dalam basis kode yang sudah ada
Mengubah interface menjadi type, atau sebaliknya, biasanya aman untuk bentuk objek biasa, karena TypeScript membandingkan tipe berdasarkan strukturnya, bukan berdasarkan namanya. Beberapa hal yang masih perlu diperiksa sebelum Anda beralih:
- Mengonversi antarmuka ke alias tipe menghilangkan penggabungan deklarasi, sehingga deklarasi kedua dengan nama yang sama menjadi kesalahan pengidentifikasi duplikat.
- Mengonversi alias tipe menjadi antarmuka hanya berfungsi untuk bentuk objek. Serikat pekerja, tupel, dan tipe yang dipetakan harus tetap sebagai alias tipe.
- Pesan kesalahan dan kursor editor mungkin menampilkan jenis yang berbeda, yang dapat mengejutkan rekan satu tim tetapi tidak mengubah perilaku.
Lakukan perubahan dalam satu permintaan tarik terfokus, jalankan kompiler dalam mode ketat dan rangkaian pengujian Anda, dan hindari mencampurkannya dengan pekerjaan fitur sehingga peninjau dapat melihat bahwa tidak ada perubahan lain.
Penutup
Pertanyaan antarmuka vs tipe memiliki jawaban yang tenang: keduanya tumpang tindih untuk objek, masing-masing memiliki beberapa kemampuan unik, dan konsistensi lebih penting daripada pilihan. Gunakan antarmuka untuk bentuk dan tipe untuk hal lainnya, kecuali tim Anda menginginkan sebaliknya. Untuk melihat sendiri perbedaannya, salin contoh di atas ke dalam file dan jalankan tsc --noEmit --strict di dalamnya.
Pertanyaan yang sering diajukan
Apa perbedaan antara antarmuka dan mengetik di TypeScript?
Keduanya dapat mendeskripsikan bentuk objek. Hanya tipe yang dapat memberi nama gabungan, tupel, dan tipe terkomputasi, sementara hanya antarmuka yang mendukung penggabungan deklarasi.
Haruskah saya menggunakan antarmuka atau mengetik untuk alat peraga React?
Keduanya berfungsi dengan baik. Banyak tim menggunakan antarmuka untuk alat peraga, sementara yang lain lebih memilih tipe untuk konsistensi dengan serikat pekerja. Pilih satu dan terapkan di seluruh proyek.
Bisakah suatu tipe memperluas antarmuka?
Ya, dengan menggunakan persimpangan seperti tipe Admin = Pengguna & { izin: string[] }. Antarmuka juga dapat memperluas alias tipe objek.
Apakah antarmuka lebih cepat dari tipe?
Panduan kinerja TypeScript mendukung perluasan antarmuka pada persimpangan besar dalam basis kode besar. Dalam proyek-proyek biasa, perbedaannya tidak akan terlihat.
Apa itu penggabungan deklarasi?
Ini adalah ketika dua antarmuka dengan nama yang sama dalam lingkup yang sama digabungkan menjadi satu. Jenis alias tidak dapat digabungkan, dan nama duplikat menyebabkan kesalahan.
Teruslah belajar
Butuh bantuan dengan pengujian, WordPress atau SEO?
Kami membantu tim mengirimkan perangkat lunak yang lebih baik dan mengembangkan situs mereka. Beritahu kami apa yang sedang Anda kerjakan dan kami akan menyarankan langkah selanjutnya yang jelas.
Panduan lebih lanjut tentang pengujian, AI & pengembangan modern
Menikmati artikel ini? Pilih topik dan langsung masuk ke tutorial terbaru kami.
Penjelasan Halusinasi AI: Mengapa Model Bahasa Memperbaiki Masalah dan Cara Menguranginya
Halusinasi AI menjelaskan: apa itu, mengapa model bahasa memproduksinya, tipe umum, cara menguranginya dengan landasan dan petunjuk, dan pemeriksaan…
Baca artikel →DevOpsPenjelasan Variabel Lingkungan: File .env, Rahasia, dan Konfigurasi Dilakukan dengan Benar
Variabel lingkungan dijelaskan dengan contoh Python yang kami jalankan: membaca dan mengaturnya, mengapa setiap nilai berupa string, file .env, pewa…
Baca artikel →Pengembangan perangkat lunakPenjelasan Pembatasan Kecepatan API: Algoritma, Header, dan Penanganan 429 Kesalahan
Pembatasan laju API dijelaskan dengan simulasi yang kami jalankan: keranjang token, jendela tetap, jendela geser, respons 429, header batas laju, pe…
Baca artikel →Otomatisasi pengujianMengejek dengan Python: unittest.mock, patch dan Kesalahan yang Membuat Tes Berbohong
Mengejek dengan Python dengan unittest.mock, menguji: Mock dan return_value, side_effect, menambal di mana nama digunakan, spesifikasi dan autospec,…
Baca artikel →Pengujian perangkat lunakPenjelasan Cakupan Kode: Cakupan Jalur vs Cabang dan Apa Arti 100% Sebenarnya
Cakupan kode dijelaskan dengan coverage.py yang sebenarnya dijalankan: cakupan garis, cabang dan kondisi, membaca laporan, mengapa cakupan 100% masi…
Baca artikel →Basis data & SQLDELETE vs TRUNCATE vs DROP dalam SQL: Perbedaan, Rollback dan Kapan Menggunakan Masing-Masing
DELETE vs TRUNCATE vs DROP dijelaskan dengan SQL yang diuji: apa yang dihapus, rollback, pemicu, reset identitas, kecepatan, dan perbedaan PostgreSQ…
Baca artikel →Basis data & SQLPenjelasan Tampilan SQL: Membuat, Menggunakan, dan Menghindari Kesalahan, Dengan Contoh
Tampilan SQL dijelaskan dengan kueri yang kami jalankan: membuat tampilan, hasil langsung, menyembunyikan kolom, kinerja, tampilan yang dapat diperb…
Baca artikel →Pengembangan perangkat lunakAntarmuka TypeScript vs Tipe: Perbedaan Nyata, Diuji Dengan Kompiler
Antarmuka TypeScript vs tipe, diperiksa dengan kompiler sebenarnya: apa yang bisa dilakukan keduanya, apa yang hanya bisa dilakukan satu orang, peng…
Baca artikel →Pengembangan perangkat lunakPenjelasan Python *args dan **kwargs: Fungsi Fleksibel Dengan Contoh Jelas
Python *args dan **kwargs dijelaskan dengan kode yang kami jalankan: pengepakan dan pembongkaran, urutan parameter, argumen hanya kata kunci dan pos…
Baca artikel →Pengembangan perangkat lunakFungsi Python Lambda: Sintaks, Kegunaan Sebenarnya, dan Kapan Tidak Digunakan
Fungsi python lambda dijelaskan dengan kode yang kami jalankan: sintaksis, pengurutan dengan kunci, peta dan filter, penutupan, jebakan pengikatan a…
Baca artikel →Kecerdasan buatanApa Itu Agen AI? Cara Kerjanya, Dengan Agent Loop Sederhana yang Dapat Anda Jalankan
Apa itu agen AI? Panduan sederhana tentang loop agen, alat, memori, dan pagar pembatas, dengan loop Python kecil yang kami jalankan, risiko nyata da…
Baca artikel →DevOpsPemantauan vs Observabilitas: Perbedaan Nyata, Dengan Log, Metrik, dan Jejak
Penjelasan pemantauan vs observabilitas: kegagalan yang diketahui dan tidak diketahui, log, metrik dan jejak, penelusuran insiden checkout, sinyal e…
Baca artikel →DevOpsVolume Docker vs Bind Mounts: Pertahankan Data Kontainer dengan Cara yang Benar
Volume Docker vs pengikatan pengikat dijelaskan: mengapa data kontainer menghilang, volume yang diberi nama, pengikatan pengikatan, tmpfs, contoh Tu…
Baca artikel →Otomatisasi pengujianTDD vs BDD: Perbedaan Utama, Satu Fitur Dibangun dengan Dua Cara dan Kapan Menggunakan Masing-masing
TDD vs BDD dijelaskan dengan satu fitur diskon yang dibuat dengan dua cara: refactor merah-hijau dengan kode yang kami jalankan, skenario Mengingat-…
Baca artikel →Pengembangan perangkat lunakGit merge vs rebase: perbedaan, contoh, dan kapan memakai masing-masing
Git merge vs rebase dijelaskan dengan keluaran log nyata, tabel perbandingan, aturan emas rebase, dan alur kerja tim yang aman.
Baca artikel →Pengembangan perangkat lunakList Comprehension Python: Sintaks, Contoh, dan Kapan Harus Dihindari
List comprehension Python dijelaskan: sintaks, filter, if-else, perulangan bersarang, waktu yang diukur, dan kapan perulangan for biasa lebih baik.
Baca artikel →Basis data & SQLPenjelasan SQL JOIN dengan Contoh (Inner, Left, Right, Full)
Pahami SQL JOIN langkah demi langkah dengan tabel dan query contoh: INNER, LEFT, RIGHT, FULL, CROSS, dan SELF, plus kesalahan umum dan tips performa.
Baca artikel →