Menu

Union Type TypeScript: Operator | dan Contohnya

Union type seperti string | number berarti sebuah nilai bisa berupa salah satu dari beberapa tipe. Pelajari apa yang bisa kamu lakukan dengan union (hanya yang didukung semua anggotanya), cara mempersempitnya, union dari literal dan object type, serta perbedaan (A | B)[] dan A[] | B[].

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Union type mendaftar beberapa alternatif dengan |: nilai bertipe string | number berupa string atau number. Union adalah cara TypeScript menjelaskan nilai yang memang bisa punya lebih dari satu bentuk, dan compiler mewajibkanmu mengecek bentuk mana yang kamu pegang sebelum memakai apa pun yang khusus untuk bentuk itu.

Di dalam setiap cabang pemeriksaan typeof, id hanya punya satu tipe. Langkah itu disebut narrowing, dan itulah yang membuat union praktis dipakai.

Hanya Member Bersama yang Boleh Dipakai

Sebelum narrowing, kamu hanya bisa memakai apa yang didukung setiap anggota union. toString() ada di string maupun number, jadi boleh dipakai; toUpperCase() hanya ada di string:

index.ts(3,16): error TS2339: Property 'toUpperCase' does not exist on type 'string | number'.
  Property 'toUpperCase' does not exist on type 'number'.

Baris kedua menyebutkan anggota yang tidak punya property itu. Aturan yang sama berlaku ke arah sebaliknya: nilai string | number tidak bisa diberikan ke parameter bertipe string (TS2345), karena nilainya mungkin number. Union menerima lebih banyak nilai, dan sebagai gantinya membatasi apa yang bisa kamu lakukan dengan nilai itu sampai kamu memeriksanya.

Mempersempit Union

Narrowing memakai pemeriksaan JavaScript biasa. TypeScript mengikuti alur kontrol dan membuang anggota yang sudah tersingkir, jadi setelah pemeriksaan terakhir hanya satu anggota yang tersisa:

PemeriksaanMempersempitCocok untuk
typeof x === "string"ke tipe primitifnyastring, number, boolean, bigint, symbol, undefined, function
x === null, x === "a"ke nilai yang dibandingkannull, undefined, anggota literal
Array.isArray(x)ke anggota arrayarray
x instanceof Dateke class-nyainstance class
"meow" in xke anggota yang punya property ituobject type
x.kind === "circle"ke anggota dengan penanda itudiscriminated union
isCat(x) (mengembalikan x is Cat)ke apa yang dinyatakan fungsi ituapa saja, logika khusus

Daftar lengkap bentuk narrowing ada di halaman type narrowing.

Union dari Tipe Literal

Union dari nilai literal adalah himpunan tertutup dari nilai yang diizinkan. Inilah union yang paling umum dalam kode nyata:

type Status = "idle" | "loading" | "success" | "error";
type Dice = 1 | 2 | 3 | 4 | 5 | 6;
type Toggle = "on" | "off" | boolean; // boolean is itself true | false

let current: Status = "idle";
current = "loading";   // fine
current = "finished";  // error TS2322: Type '"finished"' is not assignable to type 'Status'.

Membandingkan dengan literal akan mempersempit tipe: setelah if (current === "error"), cabang else tahu bahwa current adalah salah satu dari tiga nilai lainnya. Union literal menggantikan enum di banyak codebase; lihat tipe literal untuk as const dan cara menurunkan union seperti itu dari sebuah array.

Union dari Object Type

Ketika anggotanya berupa object type, property yang dimiliki semuanya bisa langsung dipakai. Untuk yang lainnya, cek dulu keberadaan property itu dengan in:

Untuk union dari beberapa bentuk object, pola yang lebih rapi adalah property literal bersama seperti kind: "cat" / kind: "fish". Memeriksa satu property itu mempersempit seluruh object, dan switch atas property itu bisa diperiksa kelengkapannya. Pola itu disebut discriminated union.

Array dan Union

Letak tanda kurung mengubah artinya sama sekali:

TipeArtinyaContoh nilai
(string | number)[]array yang setiap elemennya berupa string atau number[1, "two", 3]
string[] | number[]array yang hanya berisi string, atau array yang hanya berisi number["a", "b"]
string | number[]sebuah string, atau array berisi number (| mengikat lebih longgar daripada [])"text"

Saat melakukan iterasi pada (string | number)[], setiap elemen bertipe union dan perlu dipersempit, seperti di callback reduce di atas. Method seperti map dan filter juga bekerja pada string[] | number[], dengan callback yang menerima string | number.

Union dengan null dan undefined

Union yang paling umum dari semuanya adalah "sebuah nilai atau tidak ada": string | null, User | undefined. Itulah yang dikembalikan Array.prototype.find dan Map.prototype.get, dan property opsional name?: string terbaca sebagai string | undefined. Cara menanganinya dengan ?., ?? dan pemeriksaan null punya halamannya sendiri: null dan undefined.

Untuk membuang anggota dari union yang sudah ada di tingkat tipe, pakai utility bawaan: Exclude<"a" | "b" | "c", "a"> adalah "b" | "c", dan NonNullable<string | null> adalah string.

Pertanyaan yang sering diajukan

Apa itu union type di TypeScript?

Tipe yang terdiri dari beberapa alternatif yang digabung dengan |. Nilai bertipe string | number bisa berupa string atau number. Compiler hanya membolehkanmu memakai apa yang dimiliki semua anggotanya sampai kamu mempersempit nilai itu ke satu anggota dengan pemeriksaan seperti typeof value === "string".

Kenapa TypeScript bilang sebuah property tidak ada pada union type?

Karena setidaknya satu anggota union tidak memilikinya. Error TS2339, misalnya Property 'toUpperCase' does not exist on type 'string | number', berarti nilainya mungkin berupa number, yang tidak punya toUpperCase. Persempit dulu (typeof, in, Array.isArray, instanceof, atau pemeriksaan diskriminan), lalu pakai property yang khusus untuk anggota itu.

Bagaimana cara mendeklarasikan array yang berisi lebih dari satu tipe?

Letakkan union di dalam tanda kurung: (string | number)[] atau Array<string | number>, di mana setiap elemen bisa berupa salah satu tipe. string[] | number[] berbeda: seluruh array berisi string semua atau number semua. Tanpa tanda kurung, string | number[] berarti sebuah string atau array berisi number.

Apa perbedaan union type dan intersection type?

Union A | B adalah nilai yang berupa salah satu tipe, jadi kamu hanya bisa memakai apa yang dimiliki keduanya. Intersection A & B adalah nilai yang sekaligus berupa kedua tipe, jadi ia punya semua member dari keduanya. Untuk object type, A | B menerima lebih banyak nilai, sedangkan A & B mewajibkan lebih banyak property.

Bagaimana cara mengecek tipe mana yang dimiliki nilai union?

Pakai pemeriksaan runtime yang dipahami TypeScript: typeof x === "string" untuk tipe primitif, Array.isArray(x) untuk array, x instanceof Date untuk class, "prop" in x untuk bentuk object, atau x.kind === "circle" ketika anggotanya punya penanda literal yang sama. Untuk logika khusus, tulis fungsi type guard yang mengembalikan x is T.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai