เรียนรู้การสร้างชนิดข้อมูล Range และการประยุกต์ใช้งาน
สมมติเราต้องการสร้างชนิดข้อมูล Config ใน TypeScript โดยกำหนดค่าพร็อพเพอร์ตี้ให้เป็นชื่อขึ้นต้นด้วย Num ต่อเนื่องจาก Num1 ถึง Num10 ดังนี้
1type Config = {2 Num1: number3 Num2: number4 Num3: number5 Num4: number6 Num5: number7 Num6: number8 Num7: number9 Num8: number10 Num9: number11 Num10: number12}
แค่ Num1 ถึง Num10 อาจยังไม่เดือดร้อนที่จะเขียนมันขึ้นมา แต่จินตนาการถึงเมื่อต้องสร้าง Num1 ถึง Num30 ดู เลขเยอะขนาดนี้คงไม่มีใครอยากอ่านโค้ดแล้วหละ
เราสามารถสร้างชนิดข้อมูล Range มาแก้ไขปัญหานี้ได้ โดย Range นั้นรับ Generic Parameters สองค่า ค่าแรกคือจุดเริ่มต้น ค่าถัดมาคือจุดสิ้นสุด (ผลลัพธ์ไม่รวมค่านี้) การใช้งาน Range จะคืนชนิดข้อมูลที่เป็นการรวม (Union Types) ระหว่างเหล่าตัวเลขที่เริ่มต้นด้วยค่าแรกที่ส่งมาและสิ้นสุดที่ค่าก่อนค่าสุดท้ายที่ส่งเข้ามา ตัวอย่างการเรียกใช้งาน เช่น
1// มีค่าเท่ากับ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 92Range<1, 10>34// มีค่าเท่ากับ 35 | 36 | 37 | 38 | 39 | 405Range<35, 41>
เราสามารถนำค่าจาก Range มาใช้กับ Key Remapping ใน Map Types เพื่อสร้างชื่อของพร็อพเพอร์ตี้ตามเงื่อนไขข้างต้นได้ ดังนี้
1type Config = {2 [K in Range<1, 11> as `Num${K}`]: number;3};
ผลลัพธ์ที่ได้จะเหมือนกับการประกาศชนิดข้อมูล Config ในต้นบทความ
สำหรับวิธีการสร้างชนิดข้อมูล Range นั้นอาศัยโค้ดดังต่อไปนี้
1export type PrependNumber<A extends unknown[]> = A['length'] extends infer L2 ? ((length: L, ...args: A) => void) extends (...args: infer R) => void3 ? R4 : never5 : never67export type EnumerateTo<N extends number, A extends unknown[] = []> = {8 done: A extends (infer R)[] ? R : never9 build: EnumerateTo<N, PrependNumber<A>>10}[A['length'] extends N ? 'done' : 'build']1112export type Range<From extends number, To extends number> = Exclude<13 EnumerateTo<To>,14 EnumerateTo<From>15>
ในส่วนนี้จะละการอธิบายวิธีการสร้าง Range เนื่องจากผู้เขียนจะทำการแยกส่วนอธิบายนี้ไว้เป็นอีกบทความนึง