Pertanyaan Antarmuka dan kelas dalam TypeScript


Di C # ada perbedaan yang sangat besar antara antarmuka dan kelas. Memang, kelas mewakili tipe referensi, sehingga kita benar-benar dapat membuat objek dimodelkan pada kelas itu, sementara antarmuka dimaksudkan untuk menjadi kontrak yang tanda kelas untuk memastikan keberadaan perilaku tertentu. Secara khusus kami tidak dapat membuat instance antarmuka.

Intinya dengan antarmuka adalah untuk mengekspos perilaku. Sebuah kelas mengimplementasikannya dengan memberikan satu implementasi eksplisit dari perilaku tersebut.

Dalam hal itu, meskipun antarmuka mungkin mengandung properti, sebagian besar waktu kita peduli tentang antarmuka karena masalah perilaku. Jadi sebagian besar jenis, antarmuka hanyalah kontrak perilaku.

Pada TypeScript, di sisi lain, saya telah melihat sesuatu yang membuat saya sangat tidak nyaman, dan sebenarnya saya telah melihat ini lebih dari sekali, yang merupakan alasan untuk pertanyaan ini.

Dalam satu tutorial saya melihat ini:

export interface User {
    name: string; // required with minimum 5 chracters
    address?: {
        street?: string; // required
        postcode?: string;
    }
}

Tetapi tunggu sebentar. Mengapa User adalah sebuah antarmuka? Jika kita berpikir seperti C #, User seharusnya tidak menjadi antarmuka. Sebenarnya, melihatnya, sepertinya kita mendefinisikan tipe data User, bukan kontrak perilaku.

Berpikir seperti yang kita lakukan di C #, hal yang wajar adalah ini:

export class User {
    public name: string;
    public address: Address;
}
export class Address {
    public street: string;
    public postcode: string;
}

Tetapi hal ini menggunakan antarmuka seperti yang kita lakukan dengan kelas, untuk hanya mendefinisikan tipe data, daripada mendefinisikan kontrak perilaku, tampaknya sangat umum dalam TypeScript.

Jadi apa antarmuka yang dimaksudkan untuk di dalam TypeScript? Mengapa orang menggunakan antarmuka di TypeScript seperti kita menggunakan clases di C #? Bagaimana antarmuka harus digunakan dengan benar dalam TypeScript: untuk menetapkan kontrak perilaku, atau untuk menentukan properti dan objek yang seharusnya?


18
2017-11-14 14:44


asal


Jawaban:


Pertimbangkan bahwa dalam Javascript, data sering ditukar sebagai objek biasa, seringkali melalui JSON:

let data = JSON.parse(someString);

Katakanlah ini data adalah array dari User objek, dan kami akan meneruskannya ke fungsi:

data.forEach(user => foo(user))

foo akan diketik seperti ini:

function foo(user: User) { ... }

Tapi tunggu, tidak ada gunanya kita lakukan new User! Haruskah kita? Haruskah kita harus menulis kelas User dan map semua data untuk itu, meskipun hasilnya akan persis sama, sebuah Object dengan properti? Tidak, itu akan menjadi kegilaan hanya demi memuaskan sistem jenis, tetapi tidak mengubah apa pun tentang runtime. Sederhana interface yang menggambarkan bagaimana objek tertentu diharapkan terlihat seperti (berperilaku) cukup sempurna di sini.


24
2017-11-14 15:39



Saya juga datang ke Typescript dari latar belakang C # dan bertanya-tanya hal yang sama. Saya berpikir di sepanjang garis POCO (apakah POTO hal?)

Jadi apa antarmuka yang dimaksudkan untuk di dalam TypeScript?

The Typescript Handbook tampaknya mengatakan bahwa antarmuka dimaksudkan untuk "mendefinisikan kontrak dalam kode Anda ".

Mengapa orang menggunakan antarmuka di TypeScript seperti kami menggunakan kelas di C #?

Saya setuju dengan jawaban @ deceze di sini.

John Papa memperluas topik kelas dan antarmuka pada dirinya blog. Dia menunjukkan bahwa kelas paling cocok untuk "menciptakan beberapa contoh baru, menggunakan warisan, [dan] objek tunggal". Jadi, berdasarkan maksud dari antarmuka Typescript seperti yang dijelaskan dalam Typecript Handbook dan satu pendapat pria, akan terlihat bahwa kelas tidak diperlukan untuk membuat kontrak dalam Typescript. Sebagai gantinya, Anda harus menggunakan antarmuka. (Indra C Anda masih akan tersinggung.)

Antarmuka harus digunakan dengan benar dalam TypeScript: untuk menetapkan kontrak perilaku, atau untuk menentukan properti dan objek yang seharusnya?

Jika saya memahami pertanyaannya, Anda bertanya apakah antarmuka harus ditetapkan kontrak tingkah laku


11
2018-02-25 00:00



Antarmuka dalam naskah naskah mirip dengan antarmuka dalam C # karena keduanya menyediakan kontrak. Namun bertentangan dengan antarmuka C # yang hanya berisi metode antarmuka typescript juga dapat menggambarkan bidang atau properti yang mengandung objek. Oleh karena itu mereka juga dapat digunakan untuk hal-hal yang tidak mungkin langsung dengan antarmuka C #.

Perbedaan utama antara antarmuka dan kelas dalam naskah adalah antarmuka tidak memiliki representasi runtime dan tidak akan ada kode yang dipancarkan untuk mereka. Antarmuka sangat luas digunakan. Misalnya Anda dapat menggunakan literal objek untuk membuat objek dengan memuaskan antarmuka. Seperti:

let user: User = {
  name: 'abc',
  address: {
    street: 'xyz',
  },
};

Atau Anda dapat menetapkan objek data apa pun (misalnya diterima melalui penguraian JSON) ke antarmuka (tetapi pra-pemeriksaan Anda harus menyatakan bahwa itu benar-benar data yang valid). Oleh karena itu antarmuka sangat fleksibel untuk data.

Di sisi lain kelas memiliki tipe yang terkait saat runtime dan ada kode yang dihasilkan. Anda dapat memeriksa jenis pada saat runtime instanceof dan ada rantai prototipe yang disiapkan. Jika Anda mendefinisikan User sebagai kelas itu tidak akan menjadi pengguna yang valid kecuali Anda memanggil fungsi konstruktor. Dan Anda tidak bisa begitu saja mendefinisikan jenis data apa pun yang cocok untuk menjadi User. Anda perlu membuat instance baru dan menyalin properti di atas.

Aturan pribadi saya:

  • Jika saya berurusan dengan data murni (dari berbagai sumber) saya menggunakan antarmuka
  • Jika saya memodelkan sesuatu yang memiliki identitas dan status (dan mungkin metode yang dilampirkan untuk memodifikasi negara) saya menggunakan kelas.

10
2017-11-14 19:01



Bagaimana antarmuka harus digunakan dengan benar dalam TypeScript: untuk menetapkan kontrak perilaku, atau untuk menentukan properti dan objek yang seharusnya?

Antarmuka dalam TypeScript adalah bentuk kontrak, menggambarkan struktur yang diharapkan dari suatu objek. Jika suatu nilai memiliki anotasi antarmuka tertentu, Anda mengharapkannya menjadi objek yang menampilkan anggota yang ditentukan dalam antarmuka. Anggota dapat berupa nilai atau fungsi (metode). Umumnya, perilaku mereka (badan fungsi) bukan bagian dari kontrak. Tetapi Anda dapat menentukan apakah mereka readonly atau tidak.

Jadi apa antarmuka yang dimaksudkan untuk di dalam TypeScript? Mengapa orang menggunakan antarmuka di TypeScript seperti kita menggunakan clases di C #?

Antarmuka typescript dapat memainkan peran yang sama seperti antarmuka C # jika mereka diharapkan untuk diimplementasikan oleh kelas-kelas TypeScript.

Tetapi tidak hanya kelas yang dapat mengimplementasikan antarmuka; segala jenis nilai dapat:

interface HelloPrinter {
    printHello(): void
}

Objek berikut bukan kelas tetapi tetap mengimplementasikan antarmuka:

{
    printHello: () => console.log("hello")
}

Dengan demikian kita bisa melakukannya

const o: HelloPrinter = {
    printHello: () => console.log("hello")
}

dan compiler TypeScript tidak akan mengeluh.

Objek mengimplementasikan antarmuka kami tanpa memaksa kami untuk menulis kelas.

Bekerja dengan antarmuka lebih ringan daripada bekerja dengan (antarmuka dan) kelas.

Tetapi jika Anda perlu mengetahui nama jenis (nama kelas / antarmuka) selama waktu proses maka kelas adalah pilihan yang tepat, karena nama antarmuka hanya diketahui pada waktu kompilasi.


2
2017-09-15 22:22



Dengan hanya menggunakan mekanisme deserialisasi asli, Anda tidak dapat mendesentralisasi turunan dari kelas tertentu. Anda hanya dapat deserialize ke objek-javascript biasa-tua. Objek-objek semacam itu dapat mematuhi antarmuka naskah tetapi tidak bisa menjadi instance dari kelas. Jika Anda perlu berurusan dengan data yang melintasi batas serialisasi seperti data yang diharapkan dari jejaring, gunakan antarmuka. Jika Anda perlu membuat instance baru dari nilai-nilai itu sendiri, cukup buat mereka secara harfiah atau buat fungsi kenyamanan yang mengembalikan mereka - objek yang menempel ke antarmuka itu.

Sebuah kelas dapat mengimplementasikan antarmuka, tetapi mungkin akan membingungkan jika Anda mengharapkan untuk berurusan dengan instance kelas yang dibangun secara lokal dan objek-objek biasa yang dilarutkan, yang dilarutkan. Anda tidak akan pernah dapat mengandalkan basis kelas dari objek dan karenanya tidak akan ada manfaat juga mendefinisikannya sebagai kelas untuk tujuan itu.

Saya telah berhasil menciptakan modul ServerProxy yang bertanggung jawab untuk mengirim kode bolak-balik dari webservice - panggilan layanan web dan hasil yang dikembalikan. Jika Anda mengikat untuk model knockout atau serupa, Anda dapat memiliki kelas yang merangkum model ui-bound dengan konstruktor yang tahu cara mengangkat kembali objek biasa-javascript-lama yang melekat pada kontrak antarmuka-antarmuka webservice ke sebuah instance dari kelas model Anda.


1
2017-11-14 18:46