คุณจะจำกัด type parameter ด้วย extends และกำหนดค่าเริ่มต้นเพื่อสร้าง generic API ที่ใช้งานง่าย
เปิดบทเรียนนี้ใน Kodokongeneric ที่ไม่มี constraint นั้นทึบแสง: ภายในตัวฟังก์ชัน T ไม่ให้คุณทำอะไรได้เลย คำสั่ง extends สร้างสัญญาขั้นต่ำบน type parameter ซึ่งปลดล็อกการเข้าถึง property ที่รับประกันไว้ พร้อมทั้งคงชนิดที่แม่นยำของผู้เรียกไว้ นั่นคือความแตกต่างพื้นฐานจากพารามิเตอร์ที่มีชนิดเป็น interface: constraint เก็บข้อมูลไว้ ส่วน interface ลบมันทิ้ง
function longest<T extends { length: number }>(
a: T,
b: T
): T {
return a.length >= b.length ? a : b;
}
const word = longest("hello", "worldwide");
const list = longest([1, 2], [3, 4, 5]);คู่หู K extends keyof T คือรูปแบบที่คุ้มค่าที่สุดในการใช้งานประจำวัน: มันเชื่อม type parameter สองตัวเข้าด้วยกันและรับประกันแบบ static ว่าคีย์เป็นของอ็อบเจกต์จริง ชนิดค่าที่คืน T[K] (ซึ่งเป็น indexed access type) จะติดตาม property ที่ร้องขออย่างแม่นยำ นี่คือวิธีที่ฟังก์ชันอย่าง pick หรือ pluck จากไลบรารี utility ถูกกำหนดชนิดพอดี
function getProp<T extends object, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key];
}
const config = { port: 8080, host: "localhost" };
const port = getProp(config, "port");
const host = getProp(config, "host");ค่าเริ่มต้น (T = string) ทำให้ generic ไม่จำเป็นต้องระบุ ณ จุดเรียกใช้: ผู้ใช้จะระบุ type argument ก็ต่อเมื่อต้องการเบี่ยงจากกรณีทั่วไปเท่านั้น เมื่อรวมกับ constraint (T extends X = Y) มันจะกำหนดทั้งขอบเขตและพฤติกรรมโดยปริยาย ค่าเริ่มต้นต้องเป็นไปตาม constraint มิฉะนั้นการประกาศนั้นเองจะคอมไพล์ไม่ผ่าน นี่คือรูปแบบมาตรฐานสำหรับ HTTP client, store และ typed event emitter
interface ApiResponse<T = unknown> {
status: number;
data: T;
}
async function fetchJson<T = unknown>(
url: string
): Promise<ApiResponse<T>> {
const res = await fetch(url);
return { status: res.status, data: await res.json() };
}
interface Post { id: number; title: string }
const typed = await fetchJson<Post>("/api/posts/1");
const loose = await fetchJson("/api/health");K extends keyof T รับประกันอะไรใน generic signature?longest<T extends { length: number }> มีข้อได้เปรียบอะไรเหนือ longest(a: { length: number }, b: ...) ที่ไม่ใช้ generic?<T = unknown> แทน <T = any> เป็นค่าเริ่มต้น?