circumspect
คือชุดของฟังก์ชันที่ทำให้โค้ด TypeScript/JavaScript ของคุณปลอดภัยยิ่งขึ้น ฟังก์ชันเหล่านี้ประกอบด้วย invariant
, warning
, assertNever
และอื่นๆ
มีฟังก์ชันที่เป็นประโยชน์มากมายที่สามารถทำให้โค้ดของคุณปลอดภัยยิ่งขึ้น เช่น invariant
และ assertNever
ฟังก์ชันเหล่านี้จำนวนมากพร้อมใช้งานเป็นแพ็คเกจ npm แยกกัน (เช่น invariant
) แต่การติดตั้งแพ็คเกจใหม่ (และโดยส่วนใหญ่จะเป็นการติดตั้ง @types
ด้วย) สำหรับแต่ละฟังก์ชั่นนั้นไม่สะดวกนัก นอกจากนี้ แพ็คเกจเหล่านั้นโดยทั่วไปจะส่งออกฟังก์ชันเป็นการส่งออกเริ่มต้น ทำให้การนำเข้า VSCode อัตโนมัติทำงานได้ไม่ดีนัก
ไลบรารีนี้รวมฟังก์ชันที่ทำให้โค้ดของคุณปลอดภัยยิ่งขึ้นมาไว้ในที่เดียว circumspect
เป็นที่พึ่งเดียวที่มีทั้งหมด และการนำเข้า VSCode อัตโนมัติทำงานได้ตามที่คาดไว้ เนื่องจากฟังก์ชันทั้งหมดที่ได้รับจาก circumspect
มีชื่อว่าการส่งออก
นอกจากนี้ circumspect
ยังเขียนด้วย TypeScript 100% ดังนั้นทุกฟังก์ชันจึงถูกพิมพ์อย่างเหมาะสมตามค่าเริ่มต้น ดังนั้นจึงไม่จำเป็นต้องติดตั้งแพ็คเกจ @types
แยกต่างหาก
การใช้เส้นด้าย:
yarn add circumspect
ใช้ npm:
npm install circumspect
invariant
warning
assertNever
nonNull
invariant
invariant ( value : unknown , message ?: string ) : asserts value
value: unknown
คือค่าที่เราต้องการให้แน่ใจว่าเป็นความจริง
message?: string
เป็นข้อความแสดงข้อผิดพลาดเพิ่มเติมที่จะรวมไว้ในข้อผิดพลาดที่เกิดขึ้นเมื่อ value
ที่ส่งเป็นเท็จ ข้อความแสดงข้อผิดพลาดแบบกำหนดเองนี้จะแสดงเฉพาะในการพัฒนาเท่านั้น ในการผลิต ข้อผิดพลาดทั่วไปจะแสดงแทน ( 'Invariant violation'
) และพารามิเตอร์ message
จะถูกละเว้น
asserts value
ซึ่งหมายความว่าฟังก์ชันเพียงจำกัดประเภทของ value
ให้แคบลงเพื่อให้เป็นจริงและไม่ส่งคืนอะไรเลย invariant
ทำให้มั่นใจได้ว่า value
ที่ระบุเป็นความจริง หากไม่เป็นเช่นนั้น ระบบจะแสดงข้อผิดพลาดที่มี message
ที่ระบุ (อยู่ระหว่างการพัฒนาเท่านั้น) ฟังก์ชันนี้จะจำกัดประเภทของ value
ให้แคบลงอย่างเหมาะสมโดยการยกเว้นค่าเท็จทั้งหมด (เช่น null
และ undefined
)
invariant
คงที่ควรใช้เมื่อใดก็ตามที่เรามีค่าที่อาจเป็นเท็จ แต่เรามั่นใจว่าในสถานการณ์เฉพาะ ค่านั้นจะต้องเป็นความจริง นั่นคือความจริงที่ว่าค่าที่เป็นความจริงนั้นเป็นค่าคงที่ และหากเกิดขึ้นว่าค่านั้นเป็นเท็จ ค่าคงที่จะถูกละเมิด และด้วยเหตุนี้จึงต้องเกิดข้อผิดพลาด
เนื่องจากอาร์กิวเมนต์ message
ถูกละเว้นโดยสมบูรณ์ในการผลิต คุณอาจต้องการตัดออกจากโค้ดของคุณทั้งหมดในรุ่นที่ใช้งานจริง หากต้องการดูวิธีการดังกล่าว โปรดดูส่วนการเพิ่มประสิทธิภาพ
declare const user : User | null | undefined ;
invariant ( user , 'The user is missing!' ) ;
user ; // If we get here, the type is narrowed to `User`
ในตัวอย่างนี้ วัตถุ user
อาจเป็น null
หรือ undefined
(เช่น เท็จ) หากเป็นกรณีนี้ เรามีการละเมิดค่าคงที่ และฟังก์ชัน invariant
จะหยุดทำงาน มิฉะนั้น มันก็ส่งคืนและเรารู้ว่า user
ชี้ไปที่อ็อบเจ็กต์ผู้ใช้จริงๆ
warning
warning ( value : unknown , message : string ) : void
value: unknown
คือค่าที่เราต้องการตรวจสอบ หากเป็นเท็จ จะมีการออกคำเตือนไปยังคอนโซล
message: string
เป็นข้อความเตือนที่จะถูกเขียนลงคอนโซล
void
ฟังก์ชันจะไม่ส่งคืนสิ่งใด warning
ออกคำเตือนไปยังคอนโซลพร้อม message
ที่กำหนดหาก value
ที่ระบุเป็นเท็จ คำเตือนจะออกเฉพาะในการพัฒนาเท่านั้น ในการผลิต ฟังก์ชันนี้ไม่ได้ทำอะไรเลย
ควรใช้เมื่อใดก็ตามที่เราต้องการออกคำเตือนการพัฒนาเท่านั้นหากค่าบางค่าเป็นเท็จ ซึ่งจะช่วยแนะนำนักพัฒนาในการแก้ไขปัญหาที่ไม่ร้ายแรงที่ถูกรายงานในข้อความเตือน
เนื่องจาก warning
ไม่ได้ทำอะไรเลยในการผลิต คุณอาจต้องการลบการเรียกใช้ฟังก์ชันนี้ออกจากโค้ดของคุณในบิลด์ที่ใช้งานจริงโดยสิ้นเชิง หากต้องการดูวิธีการดังกล่าว โปรดดูส่วนการเพิ่มประสิทธิภาพ
declare const mode : 'auto' | 'default' | 'slow' | 'fast' ;
warning (
mode !== 'auto' ,
'Mode "auto" has been deprecated. Please use "default" instead.' ,
) ;
ในตัวอย่างนี้ เราต้องการออกคำเตือนการเลิกใช้งานหาก mode
เป็น 'auto'
ในการทำเช่นนั้น เราต้องส่งค่าเท็จ นั่นคือสาเหตุที่เราผ่าน mode !== 'auto'
ซึ่งเป็นค่าเท็จเฉพาะเมื่อ mode
เป็น 'auto'
เท่านั้น
ในบางกรณี มันสมเหตุสมผลแล้วที่จะส่ง false
โดยตรง ตัวอย่างเช่น:
declare const languages : Language [ ] ;
declare const defaultLanguage : Language ;
declare const langName : string ;
let lang = languages . find ( ( { name } ) => name === langName ) ;
if ( ! lang ) {
warning (
false ,
`Language with name " ${ langName } " not found. Falling back to the default language.` ,
) ;
lang = defaultLanguage ;
}
assertNever
assertNever ( value : never ) : never
value: never
คือค่าหลังจากตัวแปรประเภทยูเนียนที่เป็นไปได้ทั้งหมดหมดลง never
ซึ่งหมายความว่าฟังก์ชันจะไม่ส่งคืน มันแค่ส่งข้อผิดพลาดหากเคยโทรจริง assertNever
ควรใช้เพื่อให้แน่ใจว่าตัวแปรประเภทสหภาพทั้งหมดหมดลง
หาก value
ตัวแปรยูเนียนทั้งหมดหมดลง ก็ไม่มีข้อผิดพลาดของคอมไพเลอร์เมื่อเรียก assertNever
ด้วย value
เนื่องจาก value
จะถือว่าเป็นประเภท never
ที่จุดนั้น และ ณ รันไทม์ เราจะไม่มีวันถึงจุดที่เรียก assertNever
ซึ่งหมายความว่า จะไม่มีข้อผิดพลาดเกิดขึ้น
อย่างไรก็ตาม หากตัวแปรสหภาพทั้งหมดไม่ได้ใช้หมดแล้ว เรากำลังเรียก assertNever
ด้วยอย่างอื่นที่ไม่ใช่ never
และจะมีข้อผิดพลาดของคอมไพเลอร์ที่พูดบางอย่างเช่น
Argument of type 'x' is not assignable to parameter of type 'never'.
ซึ่งเราสามารถแก้ไขได้โดยจัดการกับตัวแปรที่หายไป คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการตรวจสอบความครบถ้วนสมบูรณ์ของสหภาพและ assertNever
ในเอกสาร TypeScript
declare const state : 'loading' | 'done' | 'error' ;
switch ( state ) {
case 'loading' :
return < Loading / > ;
case 'done' :
return < Done / > ;
case 'error' :
return < Error / > ;
}
ในตัวอย่างนี้ เราจัดการสถานะที่เป็นไปได้ทั้งหมดภายในคำสั่ง switch
: 'loading'
, 'done'
และ 'error'
อย่างไรก็ตาม จะเกิดอะไรขึ้นหากในอนาคตเราเพิ่มสถานะอื่น เช่น 'pending'
?
ความจริงที่ว่าคำสั่ง switch
ไม่จัดการ 'pending'
จะถูกตรวจไม่พบ
วิธีแก้ไขคือต้องมีกรณี default
ซึ่งเรายืนยันว่าสถานะที่เป็นไปได้ทั้งหมดได้รับการจัดการแล้ว
switch ( state ) {
...
default :
return assertNever ( state ) ;
}
ดังนั้น เมื่อจัดการตัวแปรสถานะทั้งหมด เราจะไม่พบข้อผิดพลาดด้านเวลาคอมไพล์ อย่างไรก็ตาม เมื่อเราเพิ่มสถานะ 'pending'
ใหม่ เราจะได้รับข้อผิดพลาดของคอมไพเลอร์แจ้งว่า:
Argument of type 'string' is not assignable to parameter of type 'never'.
เราสามารถแก้ไขข้อผิดพลาดนี้ได้โดยจัดการสถานะ 'pending'
ภายใน switch
ดังที่คุณเห็นจากตัวอย่างนี้ assertNever
มีประโยชน์อย่างยิ่งในคำสั่ง switch
ซึ่งเราต้องการให้แน่ใจว่าจะจัดการกับกรณีที่เป็นไปได้ทั้งหมดตลอดเวลา
nonNull
nonNull < T > ( value : T | null | undefined ) : value is T
value: T | null | undefined
คือค่าที่เราต้องการตรวจสอบว่าไม่เป็น null
หรือ undefined
value is T
ซึ่งหมายความว่าฟังก์ชันส่งคืนบูลีนเพื่อระบุว่าค่าที่ส่งไม่เป็น null
หรือ undefined
วิธีนี้จะจำกัดประเภทของ value
ให้แคบลงเป็น T
(เช่น ไม่รวม null
และ undefined
) เมื่อส่งคืน true
nonNull
เป็นฟังก์ชันเพรดิเคตที่ตรวจสอบว่าค่าที่ระบุไม่ใช่ค่าว่าง เช่น ไม่ใช่ null
หรือ undefined
หลังจากการเรียกใช้ฟังก์ชัน ประเภทของ value
จะถูกจำกัดให้แคบลงอย่างเหมาะสมโดยขึ้นอยู่กับว่าส่งคืนค่า true
หรือ false
nonNull
ควรใช้ทุกครั้งที่เรามีค่าที่อาจเป็น null
, undefined
หรือทั้งสองอย่าง และเราต้องการตรวจสอบและจำกัดประเภทของค่าให้แคบลงอย่างเหมาะสม
ชื่อของฟังก์ชันนี้มาจากประเภทยูทิลิตี NonNullable
ซึ่งไม่รวมค่า null
และ undefined
จากประเภท
declare const names : ( string | null ) [ ] ;
const nonNullNames = names . filter ( nonNull ) ;
// nonNullNames has type 'string[]'
ในตัวอย่างนี้ เรามีอาร์เรย์ของชื่อที่สามารถรวมองค์ประกอบ null
บางส่วนได้ เรากรองอาร์เรย์สำหรับองค์ประกอบที่ไม่ใช่ค่าว่างทั้งหมดและรับ string[]
หากเราใช้ names.filter(x => x !== null)
แทน เราจะได้องค์ประกอบที่ไม่ใช่ null กลับมา แต่ประเภทจะยังคงเป็น (string | null)[]
เนื่องจาก TypeScript เห็นฟังก์ชันที่เราส่งผ่านไปยัง filter
เนื่องจากเพิ่งส่งคืน boolean
จึงไม่มีการจำกัดประเภทให้แคบลง
เราขอแนะนำให้ใช้ babel-plugin-dev-expression
เพื่อตัดอาร์กิวเมนต์ message
ที่ส่งไป invariant
และเพื่อลบการเรียก warning
ในเวอร์ชันที่ใช้งานจริงออกทั้งหมด
โดยพื้นฐานแล้วในการผลิต babel-plugin-dev-expression
จะแทนที่
invariant ( value , 'Value is falsy!' ) ;
กับ
if ( ! value ) {
invariant ( false ) ;
}
อาร์กิวเมนต์ message
จึงถูกถอดออก นอกจากนี้ยังลบการโทรออกเพื่อ warning
โดยสิ้นเชิง ดังนั้นเส้นแบบนี้
warning ( value , 'Value is falsy!' ) ;
จะถูกลบออก
ยินดีรับคำขอดึง หากคุณตั้งใจที่จะเปิดตัวการเปลี่ยนแปลงครั้งใหญ่ โปรดเปิดประเด็นที่เกี่ยวข้องก่อน ซึ่งเราจะหารือเกี่ยวกับสิ่งที่คุณต้องการเปลี่ยนแปลง
โปรดตรวจสอบให้แน่ใจว่าได้อัปเดตการทดสอบและ README ตามความเหมาะสม
เอ็มไอที