Vue 3 + TypeScript: คู่หูสุดแกร่งเพื่อแอปพลิเคชันขนาดใหญ่

1. 🎯 ตอนที่ 32: Vue 3 + TypeScript คู่หูสุดแกร่งเพื่อแอปพลิเคชันระดับ Enterprise
2. 📖 เปิดฉาก (The Hook)
น้องๆ เคยเจอประสบการณ์ “โค้ดพังตอนรันจริง (Runtime Error)” ไหมครับ?
ลองจินตนาการว่าเรากำลังทำเว็บ E-commerce ขนาดใหญ่ มีการดึงข้อมูล product จาก API แล้วส่งต่อข้อมูลก้อนนี้ผ่าน Props ลงไปหา Component ลูกหลานลึกถึง 5 ชั้น วันดีคืนดี ทีม Backend ดันเปลี่ยนชื่อฟิลด์จาก product.title เป็น product.name สิ่งที่เกิดขึ้นใน JavaScript ธรรมดาคือ… หน้าเว็บขาวโพลน! ผู้ใช้กดซื้อของไม่ได้ กว่าเราจะรู้ตัวก็ตอนที่ลูกค้าโทรมาด่าแล้ว เพราะ JavaScript มันเป็นภาษาแบบ “ตามใจฉัน (Loosely typed)” มันจะไม่เตือนอะไรเราเลยจนกว่าโค้ดบรรทัดนั้นจะถูกรัน
เพื่อแก้ปัญหาฝันร้ายนี้ ในหนังสือ Large Scale Apps with Vue 3 and TypeScript ของคุณ Damiano Fusco ได้แนะนำให้เราจับคู่ Vue 3 เข้ากับ TypeScript ครับ
เปรียบเทียบง่ายๆ JavaScript เหมือนการจัดปาร์ตี้ที่ใครจะเดินเข้างานก็ได้ (แล้วค่อยไปมั่วเอาข้างใน) แต่ TypeScript คือ “การ์ดหน้าผับสุดโหด” ที่จะคอยตรวจบัตรเชิญ (Type Checking) ว่าคุณชื่อตรงไหม? อายุถึงไหม? ตั้งแต่ “ตอนที่เรากำลังพิมพ์โค้ด (Development time)” เลยล่ะครับ! วันนี้พี่จะพามาดูวิธีวางโครงสร้างข้อมูลและ Props ให้แข็งแกร่งดั่งหินผากันครับ
3. 🧠 แก่นวิชา (Core Concepts)
การนำ TypeScript มาใช้กับ Vue 3 ในระดับแอปพลิเคชันขนาดใหญ่ มีหัวใจสำคัญอยู่ 3 ประการครับ:
🛡️ 1. พลังแห่ง Type Checking (ดักจับบั๊กก่อนรันจริง)
ข้อดีสูงสุดของการใช้ TypeScript คือมันช่วยเปลี่ยน Runtime Errors (บั๊กที่เกิดตอนรันเว็บ) ให้กลายเป็น Compile-time Errors (บั๊กที่เตือนตั้งแต่ตอนเขียนโค้ด) ถ้าน้องส่งข้อมูลผิดประเภท (เช่น เค้าขอตัวเลข ดันส่งข้อความไป) หรือเรียกใช้ Property ที่ไม่มีอยู่จริง VS Code จะขีดเส้นใต้สีแดงด่าเราทันที! นอกจากนี้ยังช่วยให้ระบบ Autocomplete (IntelliSense) ทำงานได้อย่างสมบูรณ์แบบสุดๆ
📂 2. การจัดระเบียบ Models (Centralized Interfaces)
ในโปรเจกต์ขนาดใหญ่ เราจะไม่เขียน Type สะเปะสะปะไว้ใน Component ครับ แต่เราจะสร้างโฟลเดอร์ src/models/ ขึ้นมาเป็นศูนย์กลางเพื่อเก็บ “แบบแปลนข้อมูล (Interfaces)” ทั้งหมด และใช้ธรรมเนียมการตั้งชื่อไฟล์ด้วยนามสกุล .interface.ts (เช่น Item.interface.ts) เพื่อให้ทีมรู้ทันทีว่าไฟล์นี้คือแบบแปลน ไม่ใช่โค้ดที่ทำงานจริง
🧩 3. การนิยาม Props ด้วย Generic Types
ในยุคของ Vue 3 <script setup> การรับ Props จะเปลี่ยนร่างไปอย่างสวยงาม เราสามารถนำ Interface ที่เราสร้างไว้ มาโยนใส่ฟังก์ชัน defineProps<...>() ได้เลย ทำให้ Component ของเรารู้ทันทีว่า “ฉันต้องการรับข้อมูลหน้าตาแบบนี้นะ ห้ามส่งอย่างอื่นมาเด็ดขาด!”

4. 💻 ร่ายมนต์โค้ด (Show me the Code)
เรามาดูวิธีการสร้างระบบ “รายการสินค้า (Items List)” ที่มีการวางโครงสร้าง Type อย่างเป็นระเบียบกันครับ
Step 1: สร้างแบบแปลนข้อมูล (Interface)
สร้างไฟล์ src/models/items/Item.interface.ts
// แยกไฟล์ Interface ออกมาเพื่อให้ Component อื่นๆ นำไปใช้ร่วมกันได้
export interface ItemInterface {
id: string;
name: string;
selected: boolean; // บังคับว่าต้องมีสถานะการเลือก (true/false)
}Step 2: สร้าง Component ลูกสำหรับแสดงผล (รับ Props)
ไฟล์ src/components/items/ItemsList.component.vue
<template>
<div class="items-list">
<h3>รายการสินค้า:</h3>
<ul>
<!-- V-for จะมี Autocomplete ให้ใช้งานได้อย่างแม่นยำ! -->
<li v-for="item in items" :key="item.id">
<!-- ถ้าเผลอพิมพ์ item.title ระบบจะแจ้งเตือน Error ทันที เพราะใน Interface มีแค่ name -->
{{ item.name }}
<span v-if="item.selected"> (เลือกแล้ว)</span>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
// 1. นำเข้าแบบแปลนที่เราสร้างไว้
import type { ItemInterface } from '@/models/items/Item.interface'
// 2. ใช้ defineProps พร้อมกับระบุ Type ผ่าน Generic <{...}>
// เป็นการบอกว่า Component นี้ขอรับ Prop ชื่อ 'items' ซึ่งต้องเป็น Array ของ ItemInterface เท่านั้น!
defineProps<{
items: ItemInterface[]
}>()
</script>Step 3: สร้าง Component แม่ (คนส่ง Data)
ไฟล์ src/App.vue
<template>
<main>
<h1>ระบบจัดการสินค้าด้วย TypeScript</h1>
<!-- ส่งข้อมูล items ลงไปให้ Component ลูก -->
<ItemsList :items="myItems" />
</main>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import ItemsList from './components/items/ItemsList.component.vue'
import type { ItemInterface } from '@/models/items/Item.interface'
// 3. กำหนด Type ให้กับ State
// ถ้าเราลืมใส่ `selected: false` ระบบ TS จะขีดแดงเตือนทันทีว่าข้อมูลไม่ครบตามแบบแปลน!
const myItems = ref<ItemInterface[]>([
{ id: '001', name: 'MacBook Pro', selected: false },
{ id: '002', name: 'iPad Air', selected: true },
{ id: '003', name: 'iPhone 15', selected: false }
])
</script>5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)
🚨 1. ศัตรูตัวร้ายที่ชื่อว่า any (The Evil ‘any’ Type)
กฎเหล็กสูงสุดในการเขียน TypeScript คือ “หลีกเลี่ยงการใช้ any ให้มากที่สุดเท่าที่จะทำได้” ครับ! การกำหนดตัวแปรหรือ Props เป็นประเภท any (เช่น items: any[]) มันคือการบอก TypeScript ว่า “ไม่ต้องตรวจหรอก ปล่อยผ่านไปเลย” ซึ่งมันทำลายเป้าหมายหลักของการใช้ TS ทิ้งทั้งหมด! ถ้าใช้ any สู้กลับไปเขียน JavaScript ธรรมดาดีกว่าครับ
💡 2. การใช้ withDefaults สำหรับกำหนดค่าเริ่มต้นให้ Props
เวลาเราใช้ <script setup lang="ts"> และระบุ Type ของ Props ผ่าน Generic (defineProps<{...}>()) เราจะไม่สามารถระบุค่า Default แบบเดิมได้ Vue 3 จึงเตรียม Helper อีกตัวมาให้ชื่อว่า withDefaults ครับ:
interface Props {
title: string;
items?: ItemInterface[]; // ใส่ ? เพื่อบอกว่าเป็น Optional (ไม่ต้องส่งมาก็ได้)
}
const props = withDefaults(defineProps<Props>(), {
title: 'รายการสินค้าเริ่มต้น',
items: () => [] // ถ้าไม่ส่ง items มา ให้ใช้ Array ว่างเป็นค่าเริ่มต้น
})🎯 3. Type-Only Imports (import type)
สังเกตในโค้ดพี่ไหมครับว่า ตอนอิมพอร์ตแบบแปลน พี่ใช้คำว่า import type { ItemInterface } การใส่คำว่า type ลงไปด้วยเป็น Best Practice ที่ช่วยบอกเครื่องมือ Build Tool (เช่น Vite) ว่า “ของชิ้นนี้เป็นแค่โครงสร้างนะ ตอนแปลงเป็น JavaScript ให้ตัดบรรทัดนี้ทิ้งไปเลยไม่ต้องเอาไปรวมให้หนักไฟล์” ทำให้แอปของเราเบาและเร็วขึ้นครับ!
6. 🏁 บทสรุป (To be continued…)
การนำ TypeScript เข้ามาผสมผสานกับ Vue 3 อาจจะดูเหมือนทำให้เราต้องเขียนโค้ดเพิ่มขึ้น (ต้องมานั่งสร้าง Interface) แต่ในความเป็นจริงแล้ว มันคือ “การลงทุนระยะยาว” ครับ สำหรับแอปพลิเคชันระดับ Enterprise ที่มีโค้ดเป็นหมื่นบรรทัดและมีนักพัฒนาทำงานร่วมกันหลายคน TypeScript จะเป็นเกราะป้องกันชั้นดีที่ช่วยลดบั๊ก เพิ่มความมั่นใจในการ Refactor โค้ด และทำให้โค้ดของเรา “อ่านตัวเองได้ (Self-documenting)” โดยไม่ต้องพึ่งคู่มือภายนอกเลยล่ะครับ
เมื่อเราได้โครงสร้างข้อมูลที่แข็งแกร่งแล้ว ในบทความถัดไป เราจะมาดูวิชาขั้นสูงเกี่ยวกับการจัดการข้อมูลเหล่านั้นเมื่อมันโตขึ้น ด้วยการใช้ Pinia State Management แบบแบ่งส่วน (Modular Store) เตรียมตัวรับมือกับความซับซ้อนอย่างมีศิลปะได้เลยครับ!
ต้องการที่ปรึกษาและพัฒนาระบบ Web Application หรือ Frontend Architecture ให้กับธุรกิจของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและพัฒนาซอฟต์แวร์แบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p