TypeScript di Vue berarti menulis <script setup lang="ts"> dan menyebut bentuk props, emits, dan ref sebagai tipe. Alat bernama vue-tsc lalu memeriksa script dan template sebelum aplikasinya dijalankan. Bayangin formulir pesanan di Warung Bu Sri yang kolomnya berlabel: "nama menu (teks)", "harga (angka)". Kasir memeriksa formulir di meja depan. Pesanan yang menulis "lima belas ribu" di kolom angka ditolak di meja itu, bukan baru ketahuan waktu piringnya sudah sampai di meja pembeli. vue-tsc itu kasirnya, dan browser itu dapurnya.
🧪 Tebakan cepat:
MenuCardmenyatakanharga: number, laluApp.vuemenulis<MenuCard nama="Nasi Goreng" harga="15000" />, tanpa titik dua. Siapa yang protes duluan:vue-tscsaat type-check, atau browser saat halamannya dibuka? Tebak dulu, jawabannya ada di bagian "Yang ditangkap vue-tsc".
lang="ts" dan defineProps berbasis tipe
<!-- src/components/MenuCard.vue -->
<script setup lang="ts">
const props = defineProps<{
nama: string
harga: number
stok?: number
}>()
const emit = defineEmits<{
tambah: [nama: string, harga: number]
}>()
function klikTambah() {
emit("tambah", props.nama, props.harga)
}
</script>
lang="ts"menyalakan TypeScript di blok script itu.defineProps<{ ... }>()menyatakan props lewat tipe saja, di antara< >, dan kurungnya kosong. Tipe TypeScript ditulis huruf kecil:string,number,boolean.?artinya opsional:stok?: numberboleh gak dikirim, dan nilainyaundefined.- Compiler Vue mengubah tipe itu jadi deklarasi props biasa. Hasil compile
MenuCard.vuedi atas:
props: {
nama: { type: String, required: true },
harga: { type: Number, required: true },
stok: { type: Number, required: false }
},
emits: ["tambah"],
Jadi build development tetap memeriksa props saat aplikasinya jalan, seperti di pelajaran props.
Nilai default dan emit bertipe
const props = withDefaults(
defineProps<{ nama: string; harga: number; stok?: number }>(),
{ stok: 0 },
)
withDefaultsmemberi nilai default untuk props berbasis tipe. Hasil compile-nyastok: { type: Number, required: false, default: 0 }.- Sejak Vue 3.5, default juga bisa ditulis saat membongkar props:
const { nama, harga, stok = 0 } = defineProps<{ ... }>(). Hasil compile-nya sama. defineEmits<{ tambah: [nama: string, harga: number] }>()menyatakan eventtambahdengan dua payload: teks lalu angka. Bentuk lama yang setara:defineEmits<{ (e: "tambah", nama: string, harga: number): void }>().defineProps<...>()gak boleh sekaligus diberi argumen biasa.defineProps<{ nama: string }>({ nama: String })gagal di-compile dengandefineProps() cannot accept both type and non-type arguments at the same time. Use one or the other.
ref bertipe
const jumlah = ref(0) // Ref<number>, ditebak dari 0
const terakhir = ref<number | null>(null) // angka, atau null sebelum ada pesanan
const keranjang = ref<{ nama: string; harga: number }[]>([])
const total = computed(() => keranjang.value.reduce((a, i) => a + i.harga, 0)) // ComputedRef<number>
- Kalau nilai awalnya sudah jelas, TypeScript menebak tipenya sendiri:
ref(0)jadiRef<number>. ref(null)ditebak sebagaiRef<null>, jaditerakhir.value = hargaditolak. Tulis tipenya di antara< >:ref<number | null>(null).- Array kosong juga perlu tipe:
ref([])gak tahu isinya apa.
Yang ditangkap vue-tsc
Proyek TypeScript dari create-vue punya script type-check yang menjalankan vue-tsc --build. Ini keluaran sungguhannya untuk harga="15000" (tipe panjang di baris terakhir dipotong di sini):
$ npm run type-check
> [email protected] type-check
> vue-tsc --build
src/App.vue:16:32 - error TS2322: Type 'string' is not assignable to type 'number'.
16 <MenuCard nama="Nasi Goreng" harga="15000" :stok="8" @tambah="tambahKeKeranjang" />
~~~~~
src/components/MenuCard.vue:4:3
4 harga: number
~~~~~
The expected type comes from property 'harga' which is declared here on type '{ readonly nama: string; ... }'
Found 1 error.
vue-tsc yang protes duluan, sebelum halamannya pernah dibuka. Itu jawaban tebakannya. Kesalahan lain yang ditangkapnya:
| Kesalahan | Pesan vue-tsc |
|---|---|
<MenuCard :harga="15000" /> tanpa nama |
error TS2345: ... diikuti Property 'nama' is missing in type '{ harga: number; ... }' |
emit("tambah", props.harga, props.nama) |
error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. |
emit("tamba", props.nama, props.harga) |
error TS2345: Argument of type '"tamba"' is not assignable to parameter of type '"tambah"'. |
const terakhir = ref(null) lalu terakhir.value = harga |
error TS2322: Type 'number' is not assignable to type 'null'. |
npm run devgak memeriksa tipe. Vite cuma membuang tipenya lalu menjalankan JavaScript-nya, jadi aplikasi yang penuh error tipe tetap terbuka. Pemeriksaan jalan dinpm run type-check, dannpm run builddi proyek create-vue ikut menjalankannya.- TypeScript gak bisa memeriksa data yang baru datang saat aplikasi jalan, misalnya hasil
fetchdari server.
Di editor latihan
Latihannya berisi dua file .vue di satu editor, masing-masing dimulai baris <!-- NamaFile.vue -->: ProfileCard.vue dan App.vue. Editor menerjemahkannya dengan compiler Vue yang sama dengan Vite (@vue/compiler-sfc), jadi <script setup lang="ts"> dan defineProps<...>() jalan seperti di proyek sungguhan:
<!-- ProfileCard.vue -->
<script setup lang="ts">
defineProps<{
nama: string
umur: number
}>()
</script>
<template>
<div>
<h2 id="name">{{ nama }}</h2>
<p id="age">{{ umur }} tahun</p>
</div>
</template>
- Compiler mengubah
defineProps<{ nama: string; umur: number }>()jadidefineProps({ nama: { type: String, required: true }, umur: { type: Number, required: true } }), lalu tipenya dihapus sebelum jalan. App.vuemeng-importProfileCard.vuedan mengirimnama="Budi"dan:umur="17", jadi tampil<h2 id="name">Budi</h2>dan<p id="age">17 tahun</p>.- Seperti
npm run dev, editor ini gak memeriksa tipe:umur="17"tetap tampil. Yang menolaknya adalahvue-tsc.
⚠️ Jebakan yang sering ketemu
- Angka tanpa titik dua.
harga="15000"mengirim teks.vue-tscmenolaknya dengan TS2322; tulis:harga="15000". ref(null)atauref([])tanpa tipe. TypeScript mengunci tipenya kenullatau array kosong. Tulisref<number | null>(null).- Mengira
npm run devsudah memeriksa tipe. Dia gak memeriksa. Jalankannpm run type-check, atau pasang ekstensi Vue di editor kode supaya error-nya langsung tampil. - Teks di latihan. Kodenya harus memuat
lang="ts"dandefineProps<dengannama: stringdanumur: number,#nameberisiBudi, dan#ageberisi17 tahun.
TL;DR: <script setup lang="ts"> menyalakan TypeScript di file .vue. Props dinyatakan lewat tipe dengan defineProps<{ nama: string; harga: number; stok?: number }>(), default lewat withDefaults atau stok = 0 saat membongkar (Vue 3.5+), dan event lewat defineEmits<{ tambah: [nama: string, harga: number] }>(). Compiler mengubah tipe itu jadi deklarasi props runtime. ref(0) ditebak sendiri, tapi ref(null) perlu ref<number | null>(null). vue-tsc (lewat npm run type-check) menangkap prop yang salah tipe, prop wajib yang hilang, dan emit yang salah nama atau urutan, sebelum browser menjalankan apa pun; npm run dev gak memeriksa tipe. Editor latihan menerjemahkan <script setup lang="ts"> seperti Vite: tipe jadi props, lalu dihapus tanpa diperiksa.