Back to notes
mastery-frontend-typescript
Featured

TypeScript for React Pros: เทคนิค Type ขั้นสูงที่มืออาชีพใช้กัน

ยกระดับการเขียน TypeScript ใน React ด้วย Discriminated Unions, Generic Components, และ Const Assertions

January 29, 20262 min read readNNexis by Seereen

ภาพรวม (Overview)

การเขียน TypeScript ใน React ไม่ใช่แค่การใส่ : string หรือ : number ไปเรื่อยๆ แต่มันคือการออกแบบ "โครงสร้างข้อมูล" ที่ทำให้เราใช้ Component ได้อย่างมั่นใจและลด Bug ได้มหาศาล วันนี้มาดูท่าที่ Pro เค้าใช้กันครับ

1. Discriminated Unions for Props

ปัญหาคลาสสิก: "ถ้ามี prop variant='success' ต้องมี prop onSuccess แต่ถ้า variant='error' ต้องมี prop errorMessage" ถ้าเขียนแบบ Optional หมด (onSuccess?: ..., errorMessage?: ...) คนเรียกใช้จะงงว่าตกลงต้องใส่อันไหน

✅ แก้ด้วย Discriminated Unions:

HLJS TYPESCRIPT
type StatusProps =
  | { status: 'loading' } // ถ้า loading ห้ามมี prop อื่น
  | { status: 'success'; data: User } // ถ้า success *ต้อง*มี data
  | { status: 'error'; error: Error }; // ถ้า error *ต้อง*มี error

function StatusMessage(props: StatusProps) {
  if (props.status === 'loading') {
    return <Spinner />
  }
  if (props.status === 'success') {
    return <div>Welcome {props.data.name}</div> // ✅ TS รู้ว่ามี data แน่นอน
  }
  return <div>Error: {props.error.message}</div> // ✅ TS รู้ว่ามี error แน่นอน
}

แบบนี้คนเรียกใช้จะใส่ Props ผิดไม่ได้เลย!

2. Generic Components

สมมติเราทำ Component List ที่รับ array อะไรก็ได้ และ render item ออกมา

❌ แบบ Any (ไม่ปลอดภัย):

HLJS TYPESCRIPT
interface ListProps {
  items: any[];
  renderItem: (item: any) => ReactNode;
}

✅ แบบ Generic (Type Safe):

HLJS TYPESCRIPT
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

// เวลาใช้ TS จะรู้เองว่า item คือ User!
<List
  items={users}
  renderItem={(user) => <div>{user.name}</div>} // ✅ user มี type auto!
/>

3. "as const" และ Derived Types

อย่าเขียน Type ซ้ำซ้อนกับ Value ให้ใช้ Value สร้าง Type แทน

❌ เขียนซ้ำ:

HLJS TYPESCRIPT
const MENU = ["Home", "About", "Contact"];
type MenuType = "Home" | "About" | "Contact"; // ถ้าแก้ MENU ต้องมาแก้ตรงนี้ด้วย ลืมแก้ก็บั๊ก

✅ Derived Type (Single Source of Truth):

HLJS TYPESCRIPT
// บอก TS ว่า array นี้เป็น Read-only Tuple นะ (ค่าไม่เปลี่ยน)
const MENU = ["Home", "About", "Contact"] as const;

// ดึง Type ออกมาจากค่าจริง
type MenuType = (typeof MENU)[number]; // 'Home' | 'About' | 'Contact'

4. Omit & Pick for Cleanup

เวลาเรา extends HTML Props บางทีเราไม่อยากได้ทุกอย่าง หรืออยากทับบางตัว

HLJS TYPESCRIPT
// อยากได้ปุ่มธรรมดา แต่บังคับว่า onClick ห้าม return อะไร
interface ButtonProps extends Omit<React.ComponentProps<"button">, "onClick"> {
  onClick: () => void;
  isLoading?: boolean;
}

สรุป

TypeScript ยิ่ง "Strict" ยิ่งดีครับ:

  1. ใช้ Discriminated Unions แทน Optional Props เยอะๆ
  2. ใช้ Generics กับ Reusable Component
  3. ใช้ as const เพื่อผูก Type กับ Value

เขียน Type ให้แข็ง แล้วตอนแก้ Logic จะพริ้วครับ!

References

Share this note

Mission Accomplished

You've reached the end of this module. Time to apply these senior mindsets to your real-world projects!

Explore more topics

© 2026 My Notes by Seereen