TypeScript adalah alat yang berkuasa untuk membina aplikasi JavaScript berskala dan hampir menjadi standard untuk projek Web JavaScript yang besar. Walau bagaimanapun, untuk pemula, TypeScript juga mempunyai beberapa perkara yang rumit, salah satunya adalah membezakan antara jenis kesatuan.
Pertimbangkan kod berikut:
Kucing antara muka { Berat: Nombor; Whiskers: Nombor; } Antara muka anjing { Berat: Nombor; Mesra: Boolean; } Let Animal: Anjing |
Ramai pemaju akan terkejut mendapati bahawa apabila mengakses animal
, hanya atribut weight
yang sah, manakala whiskers
dan atribut friendly
tidak sah. Artikel ini akan menjelaskan sebab -sebabnya.
Sebelum kita menyelam ke dalamnya, mari kita mengkaji semula jenis struktur dan nominal dengan cepat, yang akan membantu memahami perbezaan TypeScript antara jenis kesatuan.
Cara terbaik untuk memahami jenis struktur adalah membandingkannya dengan jenis nominal. Kebanyakan bahasa yang ditaip yang mungkin anda gunakan adalah ditaip secara nominal. Sebagai contoh, kod C# (Java atau C serupa):
kelas foo { public int x; } kelas blah { public int x; }
Walaupun Foo
dan Blah
mempunyai struktur yang sama, mereka tidak dapat memberikan nilai antara satu sama lain. Kod berikut:
Blah b = baru foo ();
Kesalahan berikut akan dihasilkan:
<code>无法隐式转换类型“Foo”为“Blah”</code>
Struktur kelas ini tidak penting. Pembolehubah jenis Foo
hanya boleh diberikan kepada contoh kelas Foo
(atau subkelasnya).
Typescript, sebaliknya, mengamalkan jenis struktur. TypeScript menganggap mereka serasi jika kedua -dua jenis mempunyai struktur yang sama.
Oleh itu, kod berikut berfungsi dengan baik:
kelas foo { x: nombor = 0; } kelas blah { x: nombor = 0; } Let f: foo = new blah (); Let B: blah = baru foo ();
Mari kita jelaskan ini lebih lanjut. Memandangkan kod berikut:
kelas foo { x: nombor = 0; } Biarkan f: foo;
f
ialah pembolehubah yang boleh memegang sebarang objek yang sama dengan struktur kelas Foo
, dalam kes ini, yang bermaksud x
harta yang mewakili nombor. Ini bermakna walaupun objek JavaScript biasa boleh diterima.
Biarkan f: foo; f = { x: 0 };
Mari kembali ke kod pada permulaan artikel ini:
Kucing antara muka { Berat: Nombor; Whiskers: Nombor; } Antara muka anjing { Berat: Nombor; Mesra: Boolean; }
Kami tahu:
biarkan haiwan: anjing;
Buat animal
apa -apa objek dengan struktur yang sama seperti antara muka Dog
. Jadi apa maksud kod berikut?
Let Animal: Anjing |
Ini mentakrifkan jenis animal
sebagai objek yang sepadan dengan antara muka Dog
, atau mana -mana objek yang sepadan dengan antara muka Cat
.
Jadi mengapa animal
sekarang hanya membenarkan kita mengakses atribut weight
? Ringkasnya, ia adalah kerana TypeScript tidak tahu jenisnya. TypeScript tahu animal
mestilah Dog
atau Cat
, tetapi mungkin sama ada. Jika kita dibenarkan mengakses harta friendly
, tetapi dalam contoh animal
sebenarnya Cat
dan bukan Dog
, ia boleh mengakibatkan ralat runtime. Begitu juga dengan atribut whiskers
.
Jenis Kesatuan adalah kesatuan nilai yang sah, bukan kesatuan atribut. Pemaju sering menulis kod seperti ini:
Let Animal: Anjing |
Dan mengharapkan animal
mempunyai kesatuan Dog
dan sifat Cat
. Tetapi ini adalah satu lagi kesilapan. Ini menentukan animal
mempunyai nilai yang sepadan dengan sendi Dog
yang sah dan nilai Cat
yang sah. Tetapi TypeScript hanya membolehkan anda mengakses sifat yang diketahui ada. Pada masa ini, ini bermakna semua jenis sifat dalam Kesatuan.
Sekarang, kita ada:
Let Animal: Anjing |
Apabila animal
adalah Dog
, bagaimanakah kita memperlakukannya dengan betul sebagai Dog
dan sifat akses pada antara muka Dog
, dan juga mengendalikannya ketika Cat
? Pada masa ini, kita boleh menggunakan pengendali in
. Ini adalah pengendali JavaScript lama yang anda tidak dapat melihat dengan kerap, yang membolehkan kami menguji sama ada sesuatu harta dalam objek. Contohnya:
biarkan o = {a: 12}; "A" dalam O; "X" dalam O;
Ternyata bahawa TypeScript sangat terintegrasi dengan pengendali in
. Mari lihat cara menggunakan:
Let Animal: Dog | jika ("mesra" dalam haiwan) { console.log (haiwan.friendly); } else { Console.log (Animal.Whiskers); }
Kod ini tidak akan menghasilkan kesilapan. Di dalam blok if
, TypeScript tahu bahawa terdapat harta friendly
, jadi menukarkan animal
kepada Dog
. Di dalam blok else
, TypeScript juga merawat animal
sebagai Cat
. Anda juga boleh melihat ini dalam editor kod dengan melayang tetikus anda ke atas objek animal
di blok ini.
Anda mungkin mengharapkan catatan blog berakhir di sini, tetapi malangnya, menyempitkan jenis kesatuan sangat terhad dengan memeriksa jika sifat itu wujud. Ia berfungsi dengan baik untuk jenis Dog
dan Cat
mudah kita, tetapi apabila kita mempunyai lebih banyak jenis dan lebih banyak pertindihan antara jenis ini, perkara -perkara dengan mudah dapat menjadi lebih kompleks dan rapuh.
Di sinilah membezakan jenis kesatuan yang berguna. Kami akan menyimpan segala -galanya dari sebelumnya, hanya menambah harta kepada setiap jenis, yang satu -satunya tujuannya adalah untuk membezakan (atau "membezakan") jenis ini:
Kucing antara muka { Berat: Nombor; Whiskers: Nombor; Animal_type: "kucing"; } Antara muka anjing { Berat: Nombor; Mesra: Boolean; Animal_type: "anjing"; }
Perhatikan atribut ANIMAL_TYPE
pada kedua -dua jenis. Jangan salahkan untuk rentetan dengan dua nilai yang berbeza; ANIMAL_TYPE: "CAT";
Sekarang pemeriksaan kami menjadi lebih dipercayai:
Let Animal: Dog | jika (haiwan.animal_type === "anjing") { console.log (haiwan.friendly); } else { Console.log (Animal.Whiskers); }
Pemeriksaan ini akan menjadi kebocoran dengan mengandaikan bahawa setiap jenis yang mengambil bahagian dalam kesatuan mempunyai nilai yang berbeza dari atribut ANIMAL_TYPE
.
Satu -satunya kelemahan adalah bahawa anda kini perlu berurusan dengan harta baru. Setiap kali contoh Dog
atau Cat
dicipta, anda mesti memberikan nilai yang unik untuk ANIMAL_TYPE
. Tetapi jangan bimbang tentang melupakan, kerana TypeScript akan mengingatkan anda. ?
Jika anda ingin mengetahui lebih lanjut, saya cadangkan membaca dokumentasi TypeScript mengenai jenis penyempitan. Ini akan memberi kita pandangan yang lebih mendalam mengenai apa yang kita sedang berbincang di sini. Terdapat seksyen mengenai penegasan jenis dalam pautan ini. Ini membolehkan anda menentukan pemeriksaan tersuai anda sendiri untuk menyempitkan jenis tanpa menggunakan diskriminator jenis atau bergantung pada kata kunci in
.
Pada permulaan artikel ini, saya berkata, dalam contoh berikut, mengapa weight
adalah satu -satunya harta yang boleh diakses:
Kucing antara muka { Berat: Nombor; Whiskers: Nombor; } Antara muka anjing { Berat: Nombor; Mesra: Boolean; } Let Animal: Anjing |
Apa yang kita pelajari ialah TypeScript hanya tahu animal
boleh menjadi Dog
atau Cat
, tetapi tidak kedua -duanya. Oleh itu, kita hanya boleh mendapatkan weight
, yang merupakan satu -satunya harta awam di antara keduanya.
Konsep jenis kesatuan yang membezakan adalah cara TypeScript membezakan objek ini, dan pendekatan ini sangat berskala, walaupun untuk koleksi objek yang lebih besar. Oleh itu, kita perlu membuat harta ANIMAL_TYPE
baru pada kedua -dua jenis yang memegang satu nilai literal yang boleh kita gunakan untuk memeriksa. Sudah tentu, ini adalah satu lagi perkara yang perlu dijejaki, tetapi ia juga menghasilkan hasil yang lebih dipercayai - yang mana yang kita inginkan dari TypeScript di tempat pertama.
Atas ialah kandungan terperinci Demystifying Typescript Discriminated Union. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!