React + TypeScript
React + TypeScript
Section titled “React + TypeScript”React + TypeScript เป็นมาตรฐานของ frontend development — ได้ทั้ง component type safety และ autocomplete ที่ยอดเยี่ยม
Component Props Interface
Section titled “Component Props Interface”// กำหนด Props interfaceinterface ButtonProps { label: string; variant: "primary" | "secondary" | "danger"; size?: "sm" | "md" | "lg"; // optional disabled?: boolean; onClick: () => void;}
// Function component ด้วย props typefunction Button({ label, variant, size = "md", disabled, onClick }: ButtonProps) { return ( <button className={`btn btn-${variant} btn-${size}`} disabled={disabled} onClick={onClick} > {label} </button> );}// JS ใช้ PropTypes สำหรับ runtime check (ไม่ใช่ compile-time)import PropTypes from 'prop-types';function Button({ label, variant, onClick }) { return <button className={`btn btn-${variant}`} onClick={onClick}>{label}</button>;}Button.propTypes = { label: PropTypes.string.isRequired };# Python ไม่ใช้ React — แต่ framework อย่าง Streamlit มี typed componentsimport streamlit as stst.button("Click me", on_click=lambda: print("clicked"))-- SQL ไม่มี UI components-- แต่ข้อมูลจาก SQL จะถูกนำไป type ใน ReactSELECT id, name, role FROM users WHERE active = true;Children Props
Section titled “Children Props”// ReactNode สำหรับ children ที่เป็นอะไรก็ได้interface CardProps { title: string; children: React.ReactNode; footer?: React.ReactNode;}
function Card({ title, children, footer }: CardProps) { return ( <div className="card"> <h2>{title}</h2> <div className="card-body">{children}</div> {footer && <div className="card-footer">{footer}</div>} </div> );}useState กับ TypeScript
Section titled “useState กับ TypeScript”import { useState } from "react";
interface User { id: number; name: string; email: string;}
function UserProfile() { // TS infer type จาก initial value const [count, setCount] = useState(0); // number
// ระบุ type เมื่อ initial value ไม่เพียงพอ const [user, setUser] = useState<User | null>(null); const [errors, setErrors] = useState<string[]>([]);
const handleLoad = async () => { const data: User = { id: 1, name: "สมชาย", email: "s@test.com" }; setUser(data); // type-safe! };
return ( <div> {user ? <p>{user.name}</p> : <p>Loading...</p>} <button onClick={handleLoad}>Load User</button> </div> );}Event Types
Section titled “Event Types”function SearchForm() { const [query, setQuery] = useState("");
// React.ChangeEvent สำหรับ input onChange const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { setQuery(e.target.value); };
// React.FormEvent สำหรับ form onSubmit const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); console.log("Search:", query); };
// React.MouseEvent สำหรับ onClick const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => { console.log("Clicked at:", e.clientX, e.clientY); };
return ( <form onSubmit={handleSubmit}> <input value={query} onChange={handleChange} /> <button type="submit" onClick={handleClick}>ค้นหา</button> </form> );}Generic Components
Section titled “Generic Components”// Component ที่ทำงานกับหลาย data typesinterface ListProps<T> { items: T[]; renderItem: (item: T) => React.ReactNode; keyExtractor: (item: T) => string;}
function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) { return ( <ul> {items.map(item => ( <li key={keyExtractor(item)}>{renderItem(item)}</li> ))} </ul> );}
// ใช้งาน — TS infer type T จาก items<List items={[{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]} renderItem={(user) => <span>{user.name}</span>} keyExtractor={(user) => String(user.id)}/>