Skip to content

Generics ใน TypeScript

Generics ช่วยให้เราสร้าง reusable code ที่ทำงานกับหลาย type ได้โดยไม่ต้องเสีย type safety

// ไม่มี generics — ต้องเขียนหลาย function
function getFirstString(arr: string[]): string { return arr[0]; }
function getFirstNumber(arr: number[]): number { return arr[0]; }
// มี generics — function เดียวใช้ได้กับทุก type
function getFirst<T>(arr: T[]): T {
return arr[0];
}
const name = getFirst(["Alice", "Bob"]); // type: string
const score = getFirst([95, 88, 72]); // type: number
// สอง type parameters
function makePair<A, B>(first: A, second: B): [A, B] {
return [first, second];
}
const pair = makePair("hello", 42); // type: [string, number]
// Map function
function mapArray<T, U>(arr: T[], fn: (item: T) => U): U[] {
return arr.map(fn);
}
const lengths = mapArray(["hi", "hello"], s => s.length); // number[]
// API Response wrapper
interface ApiResponse<T> {
data: T;
status: number;
message: string;
timestamp: Date;
}
interface User { id: number; name: string; }
interface Product { id: number; title: string; price: number; }
// ใช้ generic interface กับต่าง type
const userResponse: ApiResponse<User> = {
data: { id: 1, name: "สมชาย" },
status: 200,
message: "success",
timestamp: new Date()
};
const productResponse: ApiResponse<Product[]> = {
data: [{ id: 1, title: "Laptop", price: 35000 }],
status: 200,
message: "success",
timestamp: new Date()
};
// จำกัดว่า T ต้องมี property "length"
function logLength<T extends { length: number }>(item: T): void {
console.log(`Length: ${item.length}`);
}
logLength("hello"); // OK — string มี length
logLength([1, 2, 3]); // OK — array มี length
// logLength(42); // Error — number ไม่มี length
// จำกัดว่า K ต้องเป็น key ของ T
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 25 };
const name = getProperty(user, "name"); // type: string
// getProperty(user, "email"); // Error! "email" ไม่ใช่ key ของ user
// Generic ใน React-like component props
interface ListProps<T> {
items: T[];
renderItem: (item: T) => string;
onSelect?: (item: T) => void;
}
// Generic class
class DataStore<T extends { id: number }> {
private items: T[] = [];
add(item: T): void { this.items.push(item); }
findById(id: number): T | undefined {
return this.items.find(item => item.id === id);
}
getAll(): T[] { return [...this.items]; }
}
const userStore = new DataStore<User>();
userStore.add({ id: 1, name: "สมชาย" });