typescript - มีวิธีใดบ้างที่จะ "กระจาย" คุณสมบัติของวัตถุไปยังพารามิเตอร์ของการนิยามฟังก์ชัน?
อธิบายได้ดีที่สุดด้วยโค้ด:
const ROUTE_PARAMS = {
userId: 'userId',
companyId: 'companyId',
};
// Is this somehow possible?
// `typeof` is obviously not the right tool here, just used as an example.
function buildRoute(typeof ROUTE_PARAMS): string;
// Result should be similar to:
function buildRoute2(userId: string, companyId: string): string;
// 🟩 The function should be called like this:
buildRoute('some-user-id', 'some-company-id');
// 🟥 I don't want the function to accept only 1 object like this:
buildRoute({ userId: 'some-user-id', companyId: 'some-company-id' });
แนวคิดคือการมีพารามิเตอร์เส้นทางของ buildRoute ถูก “ผูก” กับอ็อบเจ็กต์ในลักษณะที่แบบไดนามิก เมื่อกำหนดพารามิเตอร์ฟังก์ชัน “ด้วยตนเอง” (เช่นใน buildRoute2) ฉันมักต้องคอยให้มันสอดคล้องกันทุกครั้งเมื่อต้องเปลี่ยนคุณสมบัติของ ROUTE_PARAMS...
ข้อมูลเพิ่มเติม
ฉันจะพยายามเพิ่มข้อมูลบางอย่างเนื่องจากคำถามของฉันด้านบนดูเหมือนไม่ชัดเจนเพียงพอ:
- ฉันกำลังมองหาวิธีอย่างชัดเจนในการ "พิมพ์" ฟังก์ชันนี้จาก วัตถุ เช่นเดียวกับที่แสดงด้านบน (
ROUTE_PARAMS) - ฉันไม่สามารถเปลี่ยนสิ่งนี้เป็นโครงสร้างอื่น (ประเภททูเพิล, อาร์เรย์ชนิดใดชนิดหนึ่ง, ...) เพราะนั่นจะต้องมีการปรับโค้ดส่วนอื่น ๆ ที่ทำงานกับอ็อบเจ็กต์
ROUTE_PARAMS - ฟังก์ชันควรรับคุณสมบัติแต่ละอย่างของวัตถุเป็นพารามิเตอร์อินพุตเดียว (เช่น จำนวนพารามิเตอร์ของฟังก์ชัน === จำนวนคุณสมบัติของวัตถุ)
ฉัน ไม่ ต้องการให้ฟังก์ชันรับคุณสมบัติทั้งหมดที่ถูกบรรจุรวมในวัตถุเดียว (ตัวอย่าง 🟩 & 🟥 ข้างต้น)
คำตอบ #1
ตอนแรก ฉันคิดว่าสิ่งที่คุณต้องการจะเป็นไปได้ง่ายโดยการใช้ตัวกระจาย (spread operator) กับชนิดทูเพิล (tuple type) ตัวอย่างเช่น,
function f(...args: [string, string]) {}
เหมือนกัน (ยกเว้นชื่อพารามิเตอร์) กับ
function f(arg0: string, arg1: string) {}
ดังนั้นเราจึงสามารถลอง:
const ROUTE_PARAMS = {
userId: 'userId',
companyId: 'companyId',
};
function buildRoute(...args: typeof ROUTE_PARAMS[keyof typeof ROUTE_PARAMS][]): void {}
อย่างไรก็ตาม, typeof ROUTE_PARAMS[keyof typeof ROUTE_PARAMS][] เป็นอาเรย์ ดังนั้นเราจึงสามารถส่งอาร์กิวเมนต์ได้ไม่จำกัดจำนวนไปยังฟังก์ชัน buildRoute ที่ได้ ซึ่งจะเหมือนกับเมื่อคุณเขียน function buildRoute(...args: string[]) นอกจากนี้ เมื่อค่าที่ใช้ไม่ใช่เพียง string เท่านั้น แต่รวมถึง เช่น number ประเภทที่อนุมานได้จะเป็น (string | number)[] และเราสามารถส่ง number ในตำแหน่งใดก็ได้
ความแตกต่างกับ f ข้างต้นคือ ประเภทของตัวแปรที่กระจายออกมาคือ tuple สำหรับ f แต่เป็น array สำหรับ buildRoute ดังนั้นเราจำเป็นต้องได้ tuple จากค่าของ ROUTE_PARAMS แต่โชคร้ายที่สิ่งนั้นไม่รองรับและจะไม่รองรับ เนื่องจากข้อเสนอที่สอดคล้องกันถูกปฏิเสธ: https://github.com/microsoft/TypeScript/issues/13298
ดังนั้นตอนนี้ฉันคิดว่าสิ่งที่คุณต้องการอาจจะเป็นไปไม่ได้กับ TypeScript
คำตอบ #2
คำตอบที่อัปเดต:
ดังที่ได้กล่าวไว้ในคำตอบของ Remirror การกระจายอาร์กิวเมนต์ฟังก์ชันไปยังชุดคุณสมบัติและประเภทเฉพาะบนตัวแปรไม่ได้รับการสนับสนุน คำตอบของ Remirror อธิบายได้ดีว่าทำไมถึงเป็นเช่นนี้
อย่างไรก็ตาม เพื่อต่อยอดคำตอบของ Remirror ให้ไวยากรณ์ดูสะอาดขึ้น คุณสามารถสร้างชนิดแบบ global ที่ใช้ generic สิ่งนี้สามารถนำกลับมาใช้ซ้ำได้ในทุกสถานที่ที่คุณต้องการโดยไม่ต้องเขียนโค้ดยาว ๆ ของ keyof ซ้ำไปซ้ำมา:
// Re-useable type
export type TypeFromVar<T> = T[keyof T][];
const ROUTE_PARAMS = {
userId: 'userId',
companyId: 'companyId',
};
const User = {
name: 'Reece',
age: 25,
isVerified: true,
}
function buildRoute(...routes: TypeFromVar<typeof ROUTE_PARAMS>) {
const [userId, companyId] = args;
// do something
}
function otherFunction(...person: TypeFromVar<typeof User>) {
const [name, age, isVerified] = args;
// do something
}
buildRoute("userId1", "companyId2"); // only accepts string parameters
otherFunction("John", 36, false); // accepts string, number and boolean parameters
คำตอบต้นฉบับ:
นอกจากนี้ หากคุณสามารถกำหนดประเภทอาร์เรย์สำหรับตัวแปรของคุณ คุณสามารถรับจำนวนอาร์กิวเมนต์ที่แน่นอนและประเภทของมันได้โดยทำแบบนี้:
type RouteParams = [
userId: string,
companyId: string,
]
function buildRoute(...routes: RouteParams): string {
const [userId, companyId] = routes;
// do something
}
buildRoute("user1", "company2")
