typescript - อย่าขยายชนิดลิเทอรัลที่เป็นไปได้ในลิเทอรัลของออบเจ็กต์
ฉันมักจะใช้วัตถุที่ไม่เปลี่ยนแปลงซึ่งประกอบด้วยสตริงและตัวเลข ตัวอย่างเช่น:
const InternalServerError = {
status: 500,
message: 'Internal Server Error'
}
ฉันไม่เคยเปลี่ยนคุณสมบัติ ดังนั้นฉันจึงอยากให้ประเภทของ InternalServerError ใช้ตัวเลขและสตริงลิตเทอรัลแบบนี้:
{
status: 500,
message: 'Internal Server Error'
}
อย่างไรก็ตาม TypeScript จะขยายประเภทในประเภทที่สืบเนื่องมาจาก InternalServerError โดยอัตโนมัติ:
{
status: number,
message: string
}
ฉันสามารถแปลงคุณสมบัติแต่ละอย่างเป็นประเภทตัวอักษรของมันได้ อย่างนี้:
const InternalServerError = {
status: 500 as 500,
message: 'Internal Server Error' as 'Internal Server Error'
}
แต่นี่มีปัญหาสองข้อ:
- การทำซ้ำ โดยเฉพาะสำหรับสตริงยาว
- สามารถแปลงค่ากับชนิดลิติรัลที่ผิดได้ (
500 as 501เป็นตัวอย่าง) และตัวคอมไพเลอร์จะไม่รายงานข้อผิดพลาด ทำให้สิ่งนี้มีความเสี่ยงต่อการพิมพ์ผิด
วิธีที่ง่ายที่สุด (มีโค้ดซ้ำหรือโค้ดพื้นฐานน้อยที่สุด) และปลอดภัยต่อชนิดข้อมูลมากที่สุด (มีความเป็นไปได้ที่ข้อผิดพลาดชนิดข้อมูลที่ไม่ได้จับได้น้อยที่สุด) ในการทำให้สิ่งนี้เกิดขึ้นคืออะไร?
คำตอบ #1
คุณสามารถสร้างฟังก์ชันช่วยเหลือพร้อมกับเจเนอริกเพื่อประมาณประเภทที่แม่นยำ (500 แทน number เป็นตัวอย่าง) :
function makeError<
S extends number,
M extends string
>(status: S, message: M): {status: S, message: M} {
return {status, message}
}
const InternalServerError = makeError(500, 'Internal Server Error')
const NotFoundError = makeError(404, 'Not found')
// Code = 500
type Code = (typeof InternalServerError)['status']
// Message = Internal Server Error
type Message = (typeof InternalServerError)['message']
