6 Code Patterns ของ TypeScript ที่ช่วยให้ Code ของคุณมีประสิทธิภาพยิ่งขึ้น

22-ธ.ค.-21

คัมภีร์เทพ IT

Developer ทุกคนล้วนต้องการให้ Code ของพวกเขามีประสิทธิภาพมากที่สุดเท่าที่จะทำได้ และบทความนี้จะมาแนะนำถึง 6 Code Patterns ของ TypeScript ที่ช่วยให้ Code ของคุณมีประสิทธิภาพยิ่งขึ้น ซึ่งไม่ซับซ้อนอะไรมากมาย และสามารถนำไปใช้ในงานได้จริง

1. ใช้ Pick ในการ Implement Interface Segregation Principle

Interface Segregation Principle ถูกนิยามว่า “ลูกค้าไม่ควรถูกบังคับให้ใช้ Interface ที่พวกเขาไม่ได้ใช้”

สมมติว่า เรามี Clients Type ซึ่งมีการใช้งานหลายที่ บางครั้งใช้เพียง Subset ของ Properties เท่านั้น ตาม Interface Segregation Principle แล้ว Function Parameter ที่มี Type ควรเป็น Type ขั้นต่ำเท่าที่จำเป็น

เราสามารถใช้ Pick Utility Type เพื่อแยก Properties ที่ไม่ได้ใช้ออกจาก Clients Type ตามที่แสดงใน Code ด้านล่าง จะมีการเลือกเฉพาะ Name และ Active Properties เพียงเท่านั้น ดังนั้น ClientSummary Type จึงเป็นตัวแทนของ Interface ที่จำเป็นและเพียงพอแล้ว

Pick utility type

อีกวิธีหนึ่งคือ การใช้ Exclude Utility Type ดังที่แสดงด้านล่างนี้:

อย่างไรก็ตาม Pick ก็มีประสิทธิภาพมากกว่า เนื่องจากไม่จำเป็นต้องมีการเปลี่ยนแปลง เมื่อมีการเพิ่ม Properties เข้าไปใน Clients Type

2. Const Assertion เพื่อรับ Types จาก Literal Expressions

as const เป็น TypeScript Construct สำหรับ Literal Values ที่เรียกว่า Const Assertion เมื่อ as const ถูกใช้ เราจะได้รับ Const Object กับทุก Property เป็น Non-widen Literal Type เราสามารถใช้มันเพื่อหา Types จาก Constants ที่ประกาศไว้ ด้วย Const Assertion

จากตัวอย่าง Code ด้านล่างนี้ โดยสรุปแล้ว เราได้รับ payGradeType และ payValueType จาก payGrades Constant ซึ่ง Types เหล่านี้สร้าง Constraint Type System ดังนั้น เมื่อมีการแก้ไข Source Constant แล้ว Types ที่เกี่ยวข้องทั้งหมดจะได้รับการ Update โดยอัตโนมัติ

Types ที่ได้รับ สามารถช่วยบังคับใช้ Type Safety จากแหล่งความจริงเพียงแหล่งเดียว (Single Source of Truth: SSOT)

3. ตรวจสอบอย่างละเอียดถี่ถ้วนด้วย "never" Type

การนำ never Type ไปประยุกต์ใช้ให้เกิดประโยชน์ก็คือ เป็น Type Guard สำหรับ Impossible Type

ตัวอย่างต่อไปนี้ แสดงวิธี Cover Possible Literal Type Values ทั้งหมด เนื่องจาก DataTypes มีเพียงแค่ 2 Literal Types คือ Client และ Order เท่านั้น จึงทำให้ไม่สามารถเข้าถึง assertUnreachable ได้

แต่ถ้า Developer คนอื่น เพิ่ม Literal Type ใหม่เข้าไปใน DataType และลืม Update ตัว Switch Statement ก็จะมีการแสดง Compile Time Error ออกมา

ด้วยการตรวจสอบ Type ที่ละเอียดถี่ถ้วน เราสามารถตรวจพบ Condition ที่หายไปใน Compile Time แทนที่จะเป็น Run Time 

4. ใช้ Opaque Type เพื่อจำลอง Behavior ของ Nominal Typing

TypeScript เป็น Structural Type System โดยใน Structural Type System แล้ว 2 Types ที่มีรูปร่างเหมือนกัน จะสามารถเข้ากัน (Compatible) ได้ และด้วยสิ่งนี้จึงทำให้ TypeScript มีความยืดหยุ่นสูง แต่ในขณะเดียวกันมันก็อาจสร้างปัญหาได้

ในตัวอย่างด้านล่างนี้ เรามี 2 Types ซึ่งก็คือ Customer และ VIPCustomer ที่ Compatible กันซึ่ง getVIPName Function ควรที่จะสามารถใช้ VIPCustomer Type Argument ได้เท่านั้น แต่ถ้ามีการใช้ Customer Type Argument โดยไม่ได้ตั้งใจ ก็จะไม่เกิด Error ใด ๆ ขึ้นมา เนื่องจากข้อกำหนดของ Structure Typing

ปัญหาข้างต้นสามารถแก้ไขได้โดย Opaque Type แม้ว่า TypeScript จะไม่ไม่รองรับ Opaque Type แต่เราก็สามารถทำงานแบบเดียวกันได้โดยใช้ Intersection Type

OpaqueType ด้านล่างนี้ ใช้ Generic Type และ Intersection Type ทำให้ตอนนี้ Type Customer และ VIPCustomer มี Structure ที่แตกต่างกัน เนื่องจาก Internal _brand Property มีอยู่ใน Compile-Time เท่านั้น จึงทำให้ไม่เกี่ยวข้องกับ Run Time

การใช้ Opaque Type สามารถทำให้ TypeScript Code ของคุณ Clean และมีประสิทธิภาพมากขึ้น เมื่อใช้ในที่ที่ถูกต้อง

5. ค้นหา Property Type จาก Object Type

TypeScript เป็นเรื่องที่เกี่ยวกับ Type บ่อยครั้งเราต้องแยก Property Type ของ Object ที่มีอยู่ ออกจาก Object Type ที่ซับซ้อน

เราใช้ Conditional Types และ never ในการกรอง Data Type Definitions ที่จำเป็นใน lookup Type Definitions ดังที่เห็นด้านล่างนี้

lookup Type อาจจะดูแล้วค่อนข้างสับสนในแวบแรก งั้นเราลองมาดูรายละเอียดของมันกัน

อย่างแรก ในการเข้าถึง Property Type เราจะสร้าง Type ใหม่โดยใช้ Recursive Type Aliases

เมื่อ Path extends keyof T เป็น Truthy แสดงว่า Full Path จะถูก Match ดังนั้นเราจึง Return Property Type ปัจจุบันกลับมา

เมื่อ Path extends keyof T เป็น Falsy เราใช้ infer Keyword เพื่อสร้าง Pattern ให้ Match กับ Path หากมัน Match กัน เราจะ Call  ไปยัง Property ในระดับถัดไป มิฉะนั้น มันจะ Return never และนั่นหมายความว่า Path ก็จะไม่ Match กับ Type

หากไม่ Match กัน ก็ให้ดำเนินการซ้ำ ๆ กับ Property ปัจจุบัน เป็น Parameter แรก

Property Type ที่สร้างขึ้น สามารถถูกใช้งานใน Functions อื่น ๆ เพื่อบังคับให้ใช้ Type Safety

6. Refactor Function ที่มี Parameters มากเกินไป ด้วย Destructing Assignments

ปัญหาทั่วไปสำหรับ TypeScript Code ก็คือ การมี Function Parameters ที่มากเกินไป

ตัวอย่างด้านล่างนี้ แสดงให้เห็นถึงปัญหา อย่างเช่น หาก Parameter Type ใหม่ (สมมติว่าคือ middleName) เป็นสิ่งที่จำเป็น ดังนั้น เราจำเป็นต้องระมัดระวังในการเพิ่ม Parameters ให้ถูกที่

จะเห็นได้ชัดว่า มันยากที่จะ Maintain นอกจากนี้ยังเป็นการยากที่จะอ่าน Caller Function เพื่อ Match กับ Argument ด้วยชื่อของมัน

ในการ Refactor มัน เราจะใช้ Object Destructuring และ Object Literals ดังที่เห็นด้านล่าง มันเป็นหนึ่งในวิธีที่หลายคนชอบเพราะมันง่าย กระชับ และอ่านง่าย

TypeScript นั้นมีความฉลาด ไม่เพียงแต่กำหนดค่าให้กับตัวแปรที่เกี่ยวข้องเท่านั้น แต่ยังอนุมาน Type ได้อย่างถูกต้องอีกด้วย

หลังจาก Refactor ใหม่แล้ว ลำดับของ Parameters ก็ไม่สำคัญอีกต่อไป คุณสามารถเพิ่มหรือลบ Property โดยที่ไม่ต้องกังวลเกี่ยวกับตำแหน่งของ Property

ที่มา:  https://betterprogramming.pub/

 

 

รับตำแหน่งงานไอทีใหม่ๆ ด้วยบริการ IT Job Alert

 

อัพเดทบทความจากคนวงในสายไอทีทาง LINE ก่อนใคร
อย่าลืมแอดไลน์ @techstarth เป็นเพื่อนนะคะ

เพิ่มเพื่อน

 

บทความล่าสุด