Apabila pengisytiharan jenis yang serupa berulang dalam TypeScript, kita mencari cara mengira jenis hasil daripada jenis input. Perkara penting bukan bilangan aksara yang lebih pendek, tetapi sama ada hubungan antara jenis jelas kepada pembaca. Artikel ini menggunakan perkhidmatan pemberitahuan penghantaran rekaan untuk meneliti jenis bersyarat dan infer, serta membezakannya daripada tugas memastikan data luaran benar-benar betul.
1. Jenis bersyarat ialah percabangan yang menerima jenis sebagai input
Dokumentasi rasmi jenis bersyarat menerangkan sintaks memilih jenis hasil menurut syarat extends. Contoh di bawah menghasilkan jenis literal boolean berdasarkan sama ada input ialah jenis rentetan. Ini bukan fungsi yang memeriksa rentetan ketika program berjalan.
type IsText<T> = T extends string ? true : false;
type NameIsText = IsText<'parcel'>; // true
type CountIsText = IsText<3>; // false
Anggap fungsi yang membuat pemberitahuan penghantaran menerima pengecam rentetan, manakala fungsi pemprosesan dalaman menerima pengecam nombor. Sebelum menggunakan jenis bersyarat, kita perlu dapat menjelaskan mengapa dua pengecam itu dibezakan. Jika maknanya benar-benar berbeza, nama berasingan membantu; jika hanya berbeza notasi, menyeragamkan format input mungkin lebih mudah dibaca. Jangan tutupi kekaburan reka bentuk data dengan teknik jenis.
Semasa menyemak jenis, tulis input dan hasil yang dijangka secara berpasangan. Memisahkan rentetan, nombor, union dan input luar jangka menjadi contoh kecil mengurangkan beban membaca pengisytiharan rumit. Semak juga sama ada hasil dalam komen sepadan dengan jenis yang disimpulkan editor. Nama jenis boleh kelihatan semula jadi walaupun hasil pengiraan sebenar berbeza.
2. Pengagihan union mengubah makna tatasusunan
Apabila parameter jenis diletakkan terus di sebelah kiri syarat, pengagihan menerapkan syarat pada setiap anggota union. Untuk mengelakkannya dan menganggap seluruh union sebagai satu, bandingkan bentuk yang dibalut dengan kurungan siku.
type SeparateLists<T> = T extends unknown ? T[] : never;
type Together<T> = [T] extends [unknown] ? T[] : never;
type A = SeparateLists<string | number>; // string[] | number[]
type B = Together<string | number>; // (string | number)[]
const a: A = ['a', 'b'];
const b: B = ['a', 1];
Yang pertama ialah tatasusunan rentetan sahaja atau nombor sahaja. Yang kedua membenarkan rentetan dan nombor bersama dalam satu tatasusunan. Hasil yang sesuai bergantung pada sama ada seluruh senarai penghantaran mesti mempunyai satu jenis kod atau setiap item boleh mempunyai jenis berbeza. Kedua-duanya memaparkan kurungan siku, tetapi kontraknya tidak sama.
Apabila timbul masalah dalam kerja sebenar, masukkan satu anggota input pada satu masa, bukannya membaca seluruh jenis utiliti rumit sekaligus. Bandingkan hasil rentetan, nombor dan union kedua-duanya. Apabila jelas sama ada pengagihan memang dimaksudkan, sebab menambah kurungan siku juga boleh diterangkan. Dalam rekod semakan jenis, sertakan contoh nilai yang mahu dibenarkan, bukan hanya hasil akhir.
3. infer menamakan dan mengeluarkan jenis daripada struktur
infer digunakan dalam jenis bersyarat untuk menamakan sebahagian struktur yang dipadankan. Contoh berikut ialah jenis kecil yang menanggalkan satu lapisan Promise.
type OneResult<T> = T extends Promise<infer Value> ? Value : T;
type Parcel = OneResult<Promise<{ tracking: string }>>;
type ParcelList = OneResult<Promise<string[]>>;
Kod ini tidak menjalankan atau menunggu kerja tak segerak. Ia hanya menyatakan bentuk hasil pada peringkat kompilasi. Nama fungsi seperti Resolved mungkin memberi gambaran bahawa nilai sebenar sudah tiba, maka lihat juga konteks penggunaan jenis ini. Menunggu ketika program berjalan masih perlu dikendalikan dalam kod tak segerak.
Jika memerlukan jenis hasil yang ditunggu secara rekursif, semak jenis utiliti standard Awaited sebelum terus memperluas contoh satu lapisan buatan sendiri. Kesederhanaan jenis pendidikan berbeza daripada keperluan alat bersama. Jika pasukan memperkenalkan utiliti baharu, dokumentasikan input yang memberi hasil berbeza daripada jenis standard dan mengapa perbezaan itu diperlukan.
4. Hubungkan nama peristiwa dengan literal templat
Jenis literal templat boleh menyatakan gabungan literal rentetan sebagai jenis. Dalam perkhidmatan penghantaran, nama peristiwa yang menggabungkan bidang dan tindakan boleh digunakan sebagai contoh.
type Scope = 'parcel' | 'address';
type Action = 'created' | 'updated';
type EventName = `${Scope}:${Action}`;
const event: EventName = 'parcel:created';
Nama yang tersalah eja boleh dikesan ketika kompilasi, tetapi sama ada semua gabungan peristiwa sah dalam perkhidmatan sebenar ialah persoalan lain. Contohnya, jika hanya peristiwa pemadaman alamat disokong, hasil darab mudah bidang dan tindakan mungkin tidak menyatakan peraturan dengan tepat. Pertimbangkan dahulu reka bentuk yang memadankan peristiwa dibenarkan dengan payload secara jelas.
Apabila peristiwa bertambah, penting juga sama ada pembaca mudah mencari nama sebenar. Daripada menyambung beberapa lapisan peraturan gabungan automatik, nama yang dihantar kepada sistem luar boleh dibuat supaya boleh dilihat dalam satu fail. Bandingkan cara ahli baharu pasukan mengesan peristiwa salah sebelum dan selepas pengabstrakan. Kecanggihan jenis dan kebolehgunaan perlu dinilai bersama.
5. JSON luaran perlu diperiksa ketika program berjalan
Memberi respons API jenis seperti User atau Parcel sahaja tidak menjamin respons sebenar mempunyai struktur itu. Lihat bentuk ringkas yang menerima nilai luar sebagai unknown, kemudian memeriksa medan yang diperlukan.
function hasTracking(value: unknown): value is { tracking: string } {
return typeof value === 'object' && value !== null
&& 'tracking' in value && typeof value.tracking === 'string';
}
const incoming: unknown = { tracking: 'DEMO-001' };
if (hasTracking(incoming)) console.log(incoming.tracking);
Pemeriksaan ini hanya memastikan medan tracking ialah rentetan. Ia tidak memastikan nombor penjejakan benar-benar wujud atau pengguna mempunyai kebenaran melihat penghantaran itu. Penyempitan jenis, peraturan perniagaan dan semakan kebenaran perlu dianggap tanggungjawab berbeza. Dokumentasi rasmi Narrowing menerangkan cara maklumat jenis disempitkan melalui syarat.
6. Urutan ringkas menyemak pilihan alat jenis
Mula-mula tulis dua nilai sebenar yang mahu dibenarkan dan dua yang mahu ditolak. Kemudian ungkapkan maknanya menggunakan union biasa dan pengisytiharan objek yang jelas. Jika hubungan berulang masih ada, penggunaan jenis bersyarat atau infer mempunyai sebab yang jelas. Jika masa membaca pengisytiharan meningkat banyak, kita juga boleh mengekstrak bahagian bersama sahaja dan membiarkan selebihnya sebagai jenis biasa.
Akhir sekali, jalankan pemeriksaan jenis dan pemeriksaan ketika pelaksanaan secara berasingan. Memastikan pengkompil menolak nama peristiwa salah dan memastikan program menerangkan ralat apabila pelayan menghantar medan yang hilang ialah tugas saling melengkapi. Selepas menguji hasil contoh kecil, hubungkannya sehingga sempadan input sebenar supaya transformasi jenis membantu reka bentuk aplikasi yang selamat.