ค้นหาเว็บไซต์

typescript - มีวิธีที่ดีกว่าในการเพิ่ม undefined และ null ให้กับประเภทมากกว่าการสร้าง generic ของตัวเองหรือไม่?


เป็นเรื่องธรรมดาพอสมควรที่จะมีเมธอดที่หนึ่งหรือหลายพารามิเตอร์สามารถเป็น null หรือ undefined (หรือบ่อยครั้งทั้งสองอย่างกับชนิดที่สืบทอดมา) ซึ่งอาจทำให้ซิกเนเจอร์ของเมธอดบางกรณียาวมากได้:

doThing(
  user: User | undefined | null, 
  thing: Thing | undefined | null, 
  ...moreArgs
): Result {
  // ...
}

ฉันรับทราบวิธีบางอย่างในการพยายามแก้ปัญหานี้ แต่ทั้งสองวิธีมีข้อเสีย

พารามิเตอร์ที่เป็นทางเลือกดีมากถ้าตัวแปรนั้นเป็นตัวเลือกจริงๆ แต่รู้สึกไม่สะดวกเมื่อวัตถุที่ส่งเข้ามาอาจเป็น null

อันนี้สั้นกว่าแต่ดูไม่ถูกต้องสำหรับฉัน:

doThing(user?: User | null, thing?: Thing | null, ...moreArgs) 

วิธีอื่นที่ฉันรู้ในการแก้ไขเรื่องนี้คือด้วยเจเนอริก:

type Nullable<T> = T | null | undefined

doThing(user: Nullable<User>, thing: Nullable<Thing>)

นี่ถือว่ามีเหตุผล แต่ผมพบว่าโครงการมักจะลงเอยด้วยการมี generic ประเภทนี้มากกว่าหนึ่ง ซึ่งถูกนำเข้าจากไลบรารีของบุคคลที่สาม ประเภทที่สืบทอดมักจะมีร่องรอยของ Maybe<T>, Nullable<T> เป็นต้น การพยายามทำให้การใช้นี้เป็นมาตรฐานในโครงการขนาดใหญ่สามารถทำได้ยากจริงๆ

นี่ดูเหมือนจะเป็นกรณีการใช้งานที่พบได้บ่อยมาก จนฉันคาดหวังว่าควรมีวิธีแก้ปัญหาที่สอดคล้องมากกว่านี้ มีวิธีที่ดีกว่าที่จะทำสิ่งนี้ไหม?

คำตอบ #1

น่าเสียดายที่ไม่มีไวยากรณ์ในตัวที่ทำหน้าที่เป็นตัวย่อในการเขียนสหภาพของประเภทกับ null และ undefined หากคุณต้องการพฤติกรรมนั้น คุณจะต้องทำด้วยตนเอง หรือกำหนดหรือเรียกใช้นำเข้าประเภทยูทิลิตี้ที่สามารถใช้ซ้ำได้เช่น

type Nullable<T> = T | null | undefined

ไม่ว่าจะดีหรือร้าย TypeScript จะไม่แนะนำประเภทยูทิลิตี้ดังกล่าวในระดับสากล ซึ่งบางครั้งมีการร้องขอและมักถูกปฏิเสธอยู่เสมอ ดูตัวอย่างได้ที่ microsoft/TypeScript#39522 เหตุผลของพวกเขาคือ:

สิ่งที่เราได้ยินจากผู้ใช้คือพวกเขาไม่ชอบเมื่อเราต้องเพิ่มประเภททั่วโลกใหม่โดยไม่จำเป็นเพราะ a) มันทำให้เกิดความขัดแย้งกับของพวกเขา และ b) เราไม่ได้เลือกคำจำกัดความเดียวกันกับที่พวกเขาใช้อยู่เสมอ

โดยทั่วไปแล้วพวกเขาจะเพิ่มประเภทเครื่องมือช่วยเพียงเมื่อประเภทนั้น จำเป็น สำหรับการสร้างไฟล์ประกาศโดยอัตโนมัติ ฉันคิดว่าประเภทเครื่องมือช่วย Omit<T, K> ถูกนำเข้ามาเพื่อเป็นตัวแทนของพฤติกรรมของตัวดำเนินการ spread บนประเภททั่วไป แต่มีนักพัฒนา TS ในโลกความเป็นจริงหลายคนที่ไม่พอใจซึ่งกำลังใช้เวอร์ชัน Omit ของตนเองที่แตกต่างเล็กน้อยตอนนี้คุณสามารถอ่านเพิ่มเติมได้ในกระทู้ทวิตเตอร์นี้ซึ่งอธิบายข้อควรระวังต่าง ๆ อย่างละเอียดมากขึ้น

เนื่องจากจนถึงตอนนี้อย่างน้อย ไฟล์ประกาศไม่จำเป็นต้องใช้ยูทิลิตี้ไทป์เพื่อเป็นตัวแทนของ | null | undefined (มันยากที่จะจินตนาการถึงสถานการณ์ที่คุณไม่สามารถแค่เขียน | null | undefined ในไฟล์ประกาศได้) จึงไม่คุ้มค่าที่ทีม TS จะนำสิ่งนี้มาใช้


นั่นหมายถึงคุณต้องสร้างมันขึ้นมาเอง หรือ นำเข้ามาจากไลบรารีประเภท TS ที่มีชื่อเสียงบางตัว เช่น U.Nullable ของ ts-toolbelt หรือ ทำงานร่วมกับนักพัฒนาคนอื่น ๆ ในโครงการขนาดใหญ่เพื่อปฏิบัติตามมาตรฐานการเขียนโค้ดที่เกี่ยวข้องกับประเภทยูทิลิตี้ ไม่มีวิธีใดที่ดีเยี่ยม แต่พวกมันคือทางเลือกที่ดีที่สุดที่คุณจะได้เมื่อไม่มีการสนับสนุนจากตัวภาษานั้นเอง