- Halo semuanya, nama saya Alexander Nikolaichev. Saya bekerja di Yandex.Cloud sebagai pengembang front-end, mengerjakan infrastruktur internal Yandex. Hari ini saya akan memberi tahu Anda tentang hal yang sangat berguna, yang tanpanya sulit membayangkan aplikasi modern, terutama dalam skala besar. Ini adalah TypeScript, pengetikan, topik yang lebih sempit - generik, dan mengapa mereka dibutuhkan.
Pertama, mari kita jawab pertanyaan mengapa TypeScript dan apa hubungannya infrastruktur dengannya. Properti utama infrastruktur kami adalah keandalannya. Bagaimana ini bisa dijamin? Pertama-tama, Anda dapat menguji.
Kami memiliki tes unit dan integrasi. Pengujian adalah praktik standar yang baik.
Anda juga perlu menggunakan peninjauan kode. Selain itu - kumpulan kesalahan. Namun, jika kesalahan terjadi, maka mekanisme khusus mengirimkannya, dan kami dapat dengan cepat memperbaiki sesuatu.
Betapa menyenangkan jika tidak membuat kesalahan sama sekali. Untuk ini, ada pengetikan, yang tidak akan memungkinkan kita mendapatkan kesalahan sama sekali. Yandex menggunakan TypeScript standar industri. Dan karena aplikasinya besar dan kompleks, kita akan mendapatkan rumus ini: jika kita memiliki frontend, pengetikan, dan bahkan abstraksi yang kompleks, maka kita pasti akan datang ke generik TypeScript. Anda tidak dapat hidup tanpa mereka.
Sintaksis
Untuk melakukan program pendidikan dasar, pertama-tama mari kita lihat dasar-dasar sintaks.
Generik di TypeScript adalah jenis yang bergantung pada jenis lain.
Kami memiliki tipe sederhana, Halaman. Kami membuat parameter dengan parameter tertentu <T>, itu ditulis melalui tanda kurung sudut. Dan kami melihat bahwa ada beberapa string, angka, tetapi <T> adalah variabel.
Selain antarmuka dan tipe, kita dapat menerapkan sintaks yang sama ke fungsi. Artinya, parameter <T> yang sama diteruskan ke argumen fungsi, dan sebagai tanggapan kami akan menggunakan kembali antarmuka yang sama, kami juga akan meneruskannya ke sana.
Panggilan umum kami juga ditulis melalui tanda kurung sudut dengan jenis yang diinginkan, seperti saat diinisialisasi.
Sintaks serupa ada untuk kelas. Kami membuang parameter ke dalam bidang pribadi, dan kami memiliki semacam pengambil. Tetapi kami tidak menulis jenisnya di sana. Mengapa? Karena TypeScript dapat menyimpulkan jenisnya. Ini adalah fitur miliknya yang sangat berguna, dan kami akan menerapkannya.
Mari kita lihat apa yang terjadi saat menggunakan kelas ini. Kami membuat sebuah instance, dan sebagai ganti parameter <T> kami, kami meneruskan salah satu elemen enumerasi. Kami membuat enumerasi - Rusia, Inggris. TypeScript memahami bahwa kita telah mengirimkan elemen dari enumerasi dan menyimpulkan jenis lang.
Tapi mari kita lihat bagaimana inferensi tipe bekerja. Jika alih-alih elemen enumerasi, kita meneruskan konstanta dari enumerasi ini, maka TypeScript memahami bahwa ini bukan seluruh enumerasi, bukan semua elemennya. Dan sudah akan ada nilai spesifik dari jenisnya, yaitu lang en, bahasa Inggris.
Jika kita melewatkan sesuatu yang lain, misalnya string, maka tampaknya itu memiliki arti yang sama dengan pencacahan. Tapi ini sudah menjadi string, tipe lain dalam TypeScript, dan kami akan mendapatkannya. Dan jika kita melewatkan sebuah string sebagai sebuah konstanta, maka alih-alih sebuah string akan ada sebuah konstanta, sebuah string literal, ini bukanlah semua string. Dalam kasus kami, akan ada string en tertentu.
Sekarang mari kita lihat bagaimana kita bisa mengembangkannya.
Kami memiliki satu parameter. Tidak ada yang menghalangi kami untuk menggunakan banyak parameter. Semuanya ditulis dipisahkan dengan koma. Dalam tanda kurung sudut yang sama, dan kami menerapkannya secara berurutan - dari yang pertama hingga yang ketiga. Kami mengganti nilai yang diinginkan saat dipanggil.
Katakanlah rangkaian literal numerik, beberapa tipe standar, rangkaian literal string. Semuanya hanya ditulis secara berurutan.
Mari kita lihat bagaimana ini terjadi pada fungsi. Kami membuat fungsi acak. Ini secara acak memberikan argumen pertama atau kedua.
Argumen pertama adalah tipe A, yang kedua adalah tipe B. Dengan demikian, penyatuan mereka dikembalikan: baik ini atau ini. Pertama-tama, kita dapat mengetikkan fungsinya secara eksplisit. Kami menunjukkan bahwa A adalah string, B adalah angka. TypeScript akan melihat apa yang telah kami tentukan secara eksplisit dan menyimpulkan jenisnya.
Tapi kita juga bisa menggunakan inferensi tipe. Hal utama adalah untuk mengetahui bahwa bukan hanya tipe yang disimpulkan, tetapi tipe terkecil yang mungkin untuk argumen tersebut.
Misalkan kita mengirimkan argumen, string literal, dan itu harus sesuai dengan tipe A, dan argumen kedua, satu, untuk tipe B. Minimum yang mungkin untuk string literal dan satu literal A dan yang sama. TypeScript akan menampilkan ini kepada kami. Ternyata jenisnya seperti penyempitan.
Sebelum beralih ke contoh berikut, kita akan melihat bagaimana tipe umumnya berhubungan satu sama lain, bagaimana menggunakan hubungan ini, bagaimana mengatur kekacauan dari semua tipe.
Hubungan tipe
Jenis secara konvensional dapat dianggap sebagai jenis himpunan. Mari kita lihat diagram, yang menunjukkan bagian dari seluruh rangkaian tipe.
Kami melihat bahwa tipe-tipe di dalamnya dihubungkan oleh semacam hubungan. Tapi yang mana? Ini adalah hubungan pengurutan parsial - yang berarti bahwa suatu jenis selalu ditentukan dengan supertipe-nya, yaitu, jenis "di atasnya", yang mencakup semua kemungkinan nilai.
Jika Anda pergi ke arah yang berlawanan, maka setiap jenis dapat memiliki subjenis, "lebih sedikit".
Apa sajakah supertipe string? Gabungan apa pun yang menyertakan string. String dengan angka, string dengan deretan angka, apa pun. Subtipe adalah semua literal string: a, b, c, atau ac, atau ab.
Tetapi penting untuk dipahami bahwa urutannya tidak linier. Artinya, tidak semua tipe bisa dibandingkan. Ini logis, dan inilah yang menyebabkan kesalahan jenis tidak cocok. Artinya, string tidak bisa begitu saja dibandingkan dengan angka.
Dan dalam urutan ini ada jenis, seolah-olah, yang paling atas - tidak diketahui. Dan yang terendah, analog dari himpunan kosong, tidak pernah. Never adalah subtipe dari jenis apa pun. Dan tidak diketahui adalah supertipe jenis apa pun.
Dan, tentu saja, ada pengecualian - apa saja. Ini adalah tipe khusus, ini mengabaikan urutan ini sama sekali, dan digunakan jika kita bermigrasi dari JavaScript ke tidak peduli tentang tipenya. Tidak disarankan untuk menggunakan apapun dari awal. Ini layak dilakukan jika kita tidak terlalu peduli dengan posisi tipe dalam urutan itu.
Mari kita lihat pengetahuan apa dari tatanan ini yang akan memberi kita.
Kami dapat membatasi parameter ke supertipe mereka. Kata kuncinya diperpanjang. Kami akan menentukan tipe, generik, yang hanya akan memiliki satu parameter. Tetapi kami akan mengatakan bahwa itu hanya bisa menjadi subtipe dari string atau string itu sendiri. Kami tidak akan dapat mentransfer nomor, ini akan menyebabkan kesalahan jenis. Jika kita secara eksplisit mengetikkan fungsinya, maka dalam parameter kita hanya dapat menentukan subtipe dari string atau string - apel dan oranye. Kedua string tersebut merupakan rangkaian dari string literal. Verifikasi berhasil.
Kami juga dapat secara otomatis menyimpulkan tipe diri kami sendiri berdasarkan argumen. Jika kita mengoper literal string, maka ini juga sebuah string. Ceknya berhasil.
Mari kita lihat bagaimana memperluas batasan ini.
Kami membatasi diri hanya pada satu baris. Tapi string adalah tipe yang terlalu sederhana. Saya ingin bekerja dengan kunci objek. Untuk bekerja dengannya, pertama-tama kita memahami bagaimana kunci objek itu sendiri dan tipenya disusun.
Kami memiliki objek tertentu. Ini memiliki beberapa jenis bidang: string, angka, nilai boolean, dan kunci berdasarkan nama. Untuk mendapatkan kuncinya, kami menggunakan kata kunci keyof. Kami mendapatkan gabungan dari semua nama kunci.
Jika kita ingin mendapatkan nilainya, kita bisa melakukannya melalui sintaks tanda kurung siku. Ini mirip dengan sintaks JS. Ini hanya mengembalikan tipe. Jika kita melewatkan seluruh subset dari kunci, maka kita mendapatkan gabungan dari semua nilai objek ini secara umum.
Jika kita ingin mendapatkan bagian, maka kita dapat menentukannya - tidak semua kunci, tetapi beberapa subset. Kami berharap untuk menerima hanya bidang yang sesuai dengan kunci yang ditentukan. Jika kita mengurangi semuanya menjadi satu kasus, ini adalah satu bidang, dan satu kunci memberikan satu nilai. Dengan cara ini Anda bisa mendapatkan bidang yang sesuai.
Mari kita lihat bagaimana menggunakan kunci objek.
Penting untuk dipahami bahwa mungkin ada tipe yang valid setelah kata kunci extends. Termasuk dibentuk dari obat generik lain atau menggunakan kata kunci.
Mari kita lihat bagaimana ini bekerja dengan keyof. Kami telah menentukan jenis CustomPick. Nyatanya, ini hampir merupakan salinan lengkap dari tipe pustaka Pilih dari TypeScript. Apa yang dia lakukan?
Ini memiliki dua parameter. Yang kedua bukan hanya parameter. Itu harus menjadi kunci yang pertama. Kami melihat bahwa kami telah memperluas keyof dari <T>. Karenanya, ini harus berupa subset dari kunci.
Selanjutnya, untuk setiap kunci K dari subset ini, kami menjalankan objek, memberikan nilai yang sama dan secara khusus menghapus opsionalitas, tanpa tanda tanya dengan sintaks. Artinya, semua bidang harus diisi.
Kami melihat aplikasinya. Kami memiliki objek, di dalamnya nama-nama bidang. Kita hanya dapat mengambil sebagian dari mereka - a, b atau c, atau semuanya sekaligus. Kami mengambil a atau c. Hanya nilai terkait yang ditampilkan, tetapi kami melihat bahwa bidang telah menjadi wajib, karena kami, secara relatif, menghapus tanda tanya. Kami mendefinisikan tipe ini, menggunakannya. Tidak ada yang mengganggu kami untuk menggunakan obat generik ini dan memasukkannya ke obat generik lain.
Bagaimana ini bisa terjadi? Kami telah menetapkan jenis lain, Kustom. Parameter kedua diperluas bukan keyof, tetapi hasil dari penerapan generik, yang telah kita tunjukkan di sebelah kanan. Bagaimana cara kerjanya, apa yang akan kita transfer ke sana?
Kami meneruskan objek apa pun dan semua kuncinya ke generik ini. Artinya, outputnya adalah salinan objek dengan semua bidang yang diperlukan. Rantai penumpukan generik ke generik lain dan seterusnya dapat dilanjutkan tanpa batas, tergantung pada tugas, dan menyusun kode. Memperkenalkan konstruksi yang dapat digunakan kembali untuk obat generik dan sebagainya.
Argumen yang ditentukan tidak harus berurutan. Jenis seperti parameter P memperluas kunci T di customPick generik. Tapi tidak ada yang mengganggu kami untuk menunjukkannya sebagai parameter pertama, dan T sebagai yang kedua. TypeScript tidak melintasi parameter secara berurutan. Dia melihat semua parameter yang telah kami tentukan. Kemudian dia memecahkan sistem persamaan tertentu, dan jika dia menemukan solusi untuk tipe yang memenuhi sistem ini, maka pemeriksaan tipe lolos.
Dalam hal ini, Anda dapat memperoleh generik yang lucu, di mana parameter saling memperluas kunci: a - ini adalah kunci b, b - kunci a. Tampaknya, bagaimana ini bisa terjadi, kunci dari kuncinya? Tetapi kita tahu bahwa string TypeScript sebenarnya adalah string JavaScript, dan string JavaScript memiliki metodenya sendiri. Karenanya, nama metode string apa pun bisa digunakan. Karena nama metode string juga merupakan string. Dan dari sana dia mendapatkan namanya.
Dengan demikian, kita dapat memperoleh batasan seperti itu, dan sistem persamaan akan diselesaikan jika kita menunjukkan tipe yang diperlukan.
Mari kita lihat bagaimana ini bisa digunakan dalam kenyataan. Kami menggunakannya untuk API. Ada situs tempat aplikasi Yandex diterapkan. Kami ingin menampilkan proyek dan layanan yang sesuai dengannya.
Dalam contoh, saya mengambil proyek untuk menjalankan mesin virtual qyp untuk pengembang. Kami tahu bahwa kami memiliki struktur objek ini di bagian belakang, kami mengambilnya dari pangkalan. Tetapi selain proyek, ada objek lain: draf, sumber daya. Dan mereka semua memiliki strukturnya sendiri.
Selain itu, kami ingin meminta bukan seluruh objek, tetapi beberapa bidang - nama dan nama layanan. Ada peluang seperti itu, backend memungkinkan Anda melewati jalur dan menerima struktur yang tidak lengkap. DeepParsial dijelaskan di sini. Kita akan belajar bagaimana mendesainnya nanti. Tetapi ini berarti bahwa bukan seluruh objek yang ditransfer, tetapi sebagian darinya.
Kami ingin menulis beberapa fungsi yang akan meminta objek-objek ini. Mari menulis di JS. Tetapi jika Anda melihat lebih dekat, Anda dapat melihat kesalahan ketik. Pada tipe "Projeact", pada path juga terdapat kesalahan ketik pada layanan. Tidak bagus, kesalahan akan terjadi saat runtime.
Varian TS tampaknya tidak jauh berbeda selain dari jalurnya. Tetapi kami akan menunjukkan bahwa, pada kenyataannya, tidak ada nilai lain di bidang Type selain yang kami miliki di backend.
Bidang jalur memiliki sintaks khusus yang tidak memungkinkan kami memilih bidang lain yang hilang. Kami menggunakan fungsi di mana kami hanya mencantumkan tingkat bersarang yang kami butuhkan dan mendapatkan objek. Faktanya, mendapatkan jalur dari fungsi ini merupakan perhatian implementasi kami. Tidak ada rahasia di sini, dia menggunakan proxy. Ini tidak begitu penting bagi kami.
Mari kita lihat bagaimana mendapatkan fungsinya.
Kami memiliki fungsi, penggunaannya. Ada struktur ini. Pertama, kami ingin mendapatkan semua nama. Kami menulis tipe di mana namanya cocok dengan struktur.
Katakanlah untuk sebuah proyek kami mendeskripsikan tipenya di suatu tempat. Dalam proyek kami, kami menghasilkan taiping dari file protobuf yang tersedia di repositori umum. Selanjutnya, kita melihat bahwa kita memiliki semua tipe yang digunakan: Project, Draft, Resource.
Mari kita lihat implementasinya. Mari kita lihat secara berurutan.
Ada sebuah fungsi. Pertama, mari kita lihat bagaimana parameternya. Hanya dengan nama-nama yang dijelaskan sebelumnya ini. Mari kita lihat hasilnya. Ini mengembalikan nilai. Mengapa demikian? Kami telah menggunakan sintaks tanda kurung siku. Tapi karena kita mengirimkan satu string ke tipe, rangkaian literal string saat digunakan selalu satu string. Tidak mungkin untuk membuat string yang merupakan proyek dan sumber daya secara bersamaan. Dia selalu satu, dan artinya juga sama.
Mari bungkus semuanya di DeepP Partial. Tipe opsional, struktur opsional. Yang paling menarik adalah parameternya. Kami meminta mereka dengan bantuan obat generik lain.
Jenis parameter generik yang juga sesuai dengan batasan pada fungsi. Itu hanya dapat menerima jenis nama - Proyek, Sumber Daya, Draf. ID, tentu saja, adalah string, kami tidak tertarik padanya. Inilah tipe yang kami tunjukkan, satu dari tiga. Saya bertanya-tanya bagaimana fungsi jalur bekerja. Ini adalah hal umum lainnya - mengapa kita tidak menggunakannya kembali. Faktanya, yang dilakukannya hanyalah membuat fungsi yang mengembalikan array apa pun, karena objek kita dapat memiliki bidang jenis apa pun, kita tidak tahu yang mana. Dalam implementasi ini, kami mendapatkan kendali atas tipe.
Jika seseorang menganggapnya sederhana, mari beralih ke struktur kontrol.
Konstruksi kontrol
Kami hanya akan mempertimbangkan dua konstruksi, tetapi mereka akan cukup untuk mencakup hampir semua tugas yang kami butuhkan.
Apa itu Tipe Kondisional? Mereka sangat mirip dengan ternark di JavaScript, hanya untuk tipe. Kami memiliki kondisi bahwa tipe a adalah subtipe dari b. Jika demikian, maka kembalikan c. Jika tidak, kembalikan d. Artinya, ini normal jika, hanya untuk tipe.
Mari kita lihat cara kerjanya. Kami akan menentukan tipe CustomExclude, yang pada dasarnya menyalin pustaka Exclude. Itu hanya membuang elemen yang kita butuhkan dari tipe union. Jika a adalah subtipe dari b, maka kembalikan kosong, jika tidak kembalikan a. Ini aneh saat Anda melihat mengapa ini berfungsi dengan gabungan.
Hukum khusus sangat berguna, yang mengatakan: jika ada gabungan dan kami memeriksa kondisi menggunakan extends, maka kami memeriksa setiap elemen secara terpisah dan kemudian menggabungkannya lagi. Ini adalah hukum transitif, hanya untuk tipe kondisional.
Saat kami menggunakan CustomExclude, kami melihat setiap item observasi secara bergantian. a mengembang a, a adalah subtipe, tetapi mengembalikan kosong; b adalah subtipe dari a? Tidak - kembali b. c bukan subtipe dari a baik, kembali c. Lalu kita gabungkan yang tersisa, semua tanda tambah, kita dapatkan b dan c. Kami membuang dan mendapatkan apa yang kami inginkan.
Teknik yang sama dapat digunakan untuk mendapatkan semua kunci tupel. Kita tahu bahwa tupel adalah larik yang sama. Artinya, ia memiliki metode JS, tetapi kami tidak membutuhkan ini, kami hanya perlu indeks. Karenanya, kami hanya membuang nama semua metode dari semua kunci tupel dan hanya mendapatkan indeks.
Bagaimana kita mendefinisikan tipe DeepP Partial yang disebutkan sebelumnya? Di sinilah rekursi digunakan untuk pertama kalinya. Kami memeriksa semua kunci objek dan melihat. Apakah nilai merupakan suatu objek? Jika demikian, terapkan secara rekursif. Jika tidak, dan ini adalah string atau angka, biarkan dan jadikan semua kolom opsional. Ini masih tipe Parsial.
Panggilan rekursif dan tipe kondisional ini benar-benar membuat TypeScript Turing lengkap. Tapi jangan terburu-buru bersukacita atas hal ini. Ini membuat Anda kesal jika Anda mencoba melakukan sesuatu seperti ini, abstraksi dengan banyak rekursif.
TypeScript memonitor ini dan melempar kesalahan bahkan pada level kompilernya. Anda bahkan tidak akan menunggu sampai sesuatu dihitung di sana. Dan untuk kasus sederhana seperti itu, di mana kami hanya memiliki satu panggilan, rekursi sangat cocok.
Mari kita lihat cara kerjanya. Kami ingin menyelesaikan masalah menambal bidang objek. Kami menggunakan cloud virtual untuk merencanakan peluncuran aplikasi, dan kami membutuhkan sumber daya.
Katakanlah kita mengambil sumber daya CPU, inti. Setiap orang membutuhkan kernel. Saya telah menyederhanakan contoh, dan hanya ada sumber daya, hanya kernel, dan itu adalah angka.
Kami ingin membuat fungsi yang menambal mereka, menambal nilai. Tambahkan kernel atau kurangi. Dalam JavaScript yang sama, seperti yang mungkin sudah Anda duga, ada kesalahan ketik. Di sini kami menambahkan angka ke string - tidak terlalu bagus.
Hampir tidak ada yang berubah di TypeScript, tetapi pada kenyataannya, kontrol di level IDE ini akan memberi tahu Anda bahwa Anda tidak dapat meneruskan apa pun selain string ini atau nomor tertentu.
Mari kita lihat bagaimana mencapai ini. Kita perlu mendapatkan fungsi seperti itu, dan kita tahu bahwa kita memiliki objek semacam ini. Anda perlu memahami bahwa kami hanya menambal nomor dan bidang. Artinya, Anda hanya perlu mendapatkan nama bidang yang ada angka. Kami hanya memiliki satu bidang, dan itu adalah angka.
Mari kita lihat bagaimana ini diterapkan di TypeScript.
Kami telah mendefinisikan sebuah fungsi. Ini hanya memiliki tiga argumen, objek yang kita tambal dan nama field. Tapi ini bukan hanya nama field. Ini hanya dapat berupa nama bidang numerik. Kami sekarang akan mencari tahu bagaimana ini dilakukan. Dan penambal itu sendiri, yang merupakan fungsi murni.
Ada fungsi impersonal tertentu, sebuah tambalan. Kami tidak tertarik dengan implementasinya, tetapi bagaimana mendapatkan tipe yang begitu menarik, untuk mendapatkan kunci tidak hanya numerik, tetapi juga bidang apa pun berdasarkan kondisi. Kami punya nomor di sini.
Marilah kita menganalisis secara berurutan bagaimana ini terjadi.
Kami melewati semua kunci dari objek yang dilewati, lalu kami melakukan prosedur ini. Mari kita lihat bahwa bidang objek adalah subtipe dari yang diinginkan, yaitu bidang numerik. Jika ya, maka penting bahwa kita tidak menuliskan nilai field, tetapi nama field, jika tidak, secara umum, tidak ada, tidak pernah.
Tapi kemudian benda aneh itu muncul. Semua bidang numerik mulai diberi nama sebagai nilai, dan semua bidang non-numerik menjadi kosong. Kemudian kami mengambil semua nilai benda aneh ini.
Namun karena semua nilai berisi kekosongan, dan kekosongan menciut saat digabungkan, hanya bidang tersebut yang tetap sesuai dengan bidang numerik. Artinya, kami hanya mendapat bidang wajib.
Contoh menunjukkan: ada objek sederhana, bidang adalah satu. Apakah ini angka? Iya. Bidang adalah angka, apakah itu angka? Iya. Baris terakhir bukanlah angka. Kami hanya mendapatkan bidang numerik yang diperlukan.
Dengan ini diselesaikan. Saya meninggalkan yang tersulit untuk yang terakhir. Ini adalah jenis inferensi - Infer. Menangkap tipe dalam konstruksi bersyarat.
Ini tidak dapat dipisahkan dari topik sebelumnya, karena hanya bekerja dengan konstruksi bersyarat.
Seperti apa bentuknya? Katakanlah kita ingin mengetahui elemen dari sebuah array. Jenis array tertentu datang, kami ingin mengetahui elemen tertentu. Kami melihat: kami menerima beberapa jenis larik. Ini adalah subtipe larik dari variabel x. Jika ya - kembalikan elemen x, array ini. Jika tidak, kembalikan kekosongan.
Dalam kondisi ini, cabang kedua tidak akan pernah dijalankan, karena kita membuat parameter tipe dengan array apa pun. Tentu saja, ini akan menjadi sebuah array dari sesuatu, karena sebuah array dari apapun tidak dapat selain memiliki elemen.
Jika kita melewatkan sebuah array string, maka sebuah string diharapkan dikembalikan kepada kita. Dan penting untuk dipahami bahwa ini bukan hanya jenis yang didefinisikan di sini. Ini secara visual jelas dari deretan string: ada string. Tetapi dengan tupel, semuanya tidak sesederhana itu. Penting bagi kita untuk mengetahui bahwa supertipe sekecil mungkin sedang ditentukan. Jelas bahwa semua larik adalah, seolah-olah, subtipe dari larik dengan salah satu atau dengan yang tidak diketahui. Pengetahuan ini tidak memberi kita apapun. Penting bagi kami untuk mengetahui seminimal mungkin.
Misalkan kita melewati tupel. Sebenarnya, tupel juga merupakan array, tetapi bagaimana kita mengetahui elemen apa yang dimiliki array ini? Jika ada tupel string dari sebuah angka, maka itu sebenarnya adalah sebuah array. Tetapi elemen tersebut harus dari jenis yang sama. Dan jika ada string dan angka, maka akan ada penyatuan.
TypeScript akan menampilkan ini, dan kita akan mendapatkan rangkaian string dan angka yang tepat untuk contoh seperti itu.
Anda tidak hanya dapat menggunakan pengambilan di satu tempat, tetapi juga variabel sebanyak yang Anda inginkan. Katakanlah kita mendefinisikan tipe yang hanya menukar elemen tupel: yang pertama dengan yang kedua. Kami mengambil elemen pertama, yang kedua dan menukarnya.
Namun nyatanya, tidak disarankan untuk terlalu menggoda dengannya. Biasanya, untuk 90% tugas, hanya satu jenis penangkapan yang cukup.
Mari kita lihat contohnya. Tujuan: Anda perlu menunjukkan, tergantung pada status permintaan, apakah opsi yang baik atau yang buruk. Berikut adalah tangkapan layar dari layanan penerapan aplikasi kami. Sebuah entitas, ReplicaSet. Jika permintaan dari backend menghasilkan kesalahan, Anda perlu membuatnya. Pada saat yang sama, ada API untuk backend. Mari kita lihat apa hubungannya Infer dengan itu.
Kami tahu bahwa kami menggunakan, pertama, redux, dan, kedua, redux thunk. Dan kita perlu mengubah library thunk untuk dapat melakukan ini. Kami memiliki cara yang buruk dan cara yang baik.
Dan kami tahu bahwa cara yang baik untuk menggunakan extraReducers di toolkit redux terlihat seperti ini. Kami tahu bahwa ada PayLoad, dan kami ingin menarik jenis kustom yang datang dari backend, tetapi tidak hanya, tetapi juga informasi tentang permintaan yang baik atau buruk: apakah ada kesalahan atau tidak. Kami membutuhkan generik untuk keluaran ini.
Saya tidak membuat perbandingan tentang JavaScript karena itu tidak masuk akal. Dalam JavaScript, pada prinsipnya, Anda tidak dapat mengontrol jenis dengan cara apa pun dan hanya mengandalkan memori. Tidak ada pilihan yang buruk di sini, karena memang tidak ada satu pun.
Kami tahu kami menginginkan tipe ini. Tetapi kami tidak hanya memiliki tindakan. Kami perlu menelepon pengiriman dengan tindakan ini. Dan kita membutuhkan tampilan ini, di mana kita perlu menampilkan kesalahan pada kunci permintaan. Artinya, Anda perlu mencampur fungsionalitas tambahan tersebut di atas redux thunk menggunakan metode withRequestKey.
Kami memiliki metode ini, tentu saja, tetapi kami juga memiliki metode API asli, getReplicaSet. Itu ditulis di suatu tempat dan kita perlu mengganti thunk redux menggunakan semacam adaptor. Mari kita lihat bagaimana melakukannya.
Kita perlu mendapatkan fungsi seperti ini. Ini adalah fakta dengan begitu banyak fungsi ekstra. Kedengarannya menakutkan, tapi jangan khawatir, sekarang kami akan membongkarnya di rak agar jelas.
Ada adaptor yang memperluas tipe pustaka asli. Kami cukup menggabungkan metode withRequestKey tambahan dan panggilan khusus untuk jenis pustaka ini. Mari kita lihat apa fitur utama dari generik, parameter apa yang digunakan.
Yang pertama hanyalah API kami, sebuah objek dengan metode. Kita bisa melakukan getReplicaSet, mendapatkan proyek, sumber daya, tidak masalah. Kami menggunakan metode tertentu dalam metode saat ini, dan parameter kedua hanyalah nama metode. Selanjutnya, kami menggunakan parameter fungsi yang kami minta, kami menggunakan jenis pustaka Parameter, ini adalah jenis TypeScript. Dan serupa, kami menggunakan tipe pustaka ReturnType untuk respons backend. Ini untuk fungsi yang dikembalikan.
Kemudian kita hanya meneruskan keluaran khusus kita ke dalam tipe AsyncThunk yang disediakan perpustakaan untuk kita. Tapi apakah kesimpulan ini? Ini adalah obat generik lainnya. Padahal, memang terlihat sederhana. Kami tidak hanya menyimpan respons dari server, tetapi juga parameter kami, apa yang telah kami lewati. Hanya untuk melacaknya di Reducer. Selanjutnya kita melihat withRequestKey. Metode kami hanya menambahkan kunci. Apa yang dia kembalikan? Adaptor yang sama karena kita dapat menggunakannya kembali. Kami tidak harus menulis denganRequestKey sama sekali. Ini hanyalah fungsi tambahan. Ini membungkus dan secara rekursif mengembalikan adaptor yang sama kepada kami, dan kami meneruskan hal yang sama di sana.
Akhirnya, mari kita lihat bagaimana menampilkan ke Reducer apa yang dikembalikan thunk ini kepada kita.
Kami memiliki adaptor ini. Hal utama yang harus diingat adalah ada empat parameter: API, metode API, parameter (masukan) dan keluaran. Kita perlu mencari jalan keluar. Namun kami ingat bahwa kami memiliki keluaran khusus: respons server dan parameter permintaan.
Bagaimana saya bisa melakukan ini dengan Infer? Kami melihat bahwa adaptor ini dipasok ke input, tetapi umumnya ada: apa saja, apa saja, apa saja, apa saja. Kita harus mengembalikan tipe ini, terlihat seperti ini, respon server dan parameter permintaan. Dan kami sedang mencari di mana pintu masuk seharusnya. Yang ketiga. Di sinilah tempat kami menempatkan jenis tangkapan kami. Kami mendapatkan pintu masuk. Demikian juga, pintu keluar berada di urutan keempat.
TypeScript didasarkan pada pengetikan terstruktur. Dia membongkar struktur ini dan memahami bahwa pintu masuk ada di sini, di tempat ketiga, dan pintu keluar ada di tempat keempat. Dan kami mengembalikan tipe yang kami inginkan.
Jadi kami mencapai inferensi tipe, kami memiliki akses ke mereka sudah di Reducer itu sendiri. Pada dasarnya tidak mungkin melakukan ini di JavaScript.