มีหลายสถานการณ์ที่จะทำให้คุณเกิดข้อผิดพลาดนี้ ในกรณีของ OP มีการกำหนดค่าไว้อย่างชัดเจนว่าเป็นสตริงที่กำหนดไว้อย่างชัดเจนเป็นสตริงดังนั้นฉันต้องสมมติว่าอาจมาจากการเลื่อนลงหรือบริการเว็บหรือสตริง JSON ดิบ
ในกรณีดังกล่าวการส่งแบบง่าย<Fruit> fruitString
หรือfruitString as Fruit
เป็นการแก้ปัญหาเพียงอย่างเดียว (ดูคำตอบอื่น ๆ ) คุณจะไม่สามารถปรับปรุงได้ในเวลารวบรวม [ แก้ไข: ดูคำตอบอื่น ๆ ของฉันเกี่ยวกับ<const>
]!
แต่มันเป็นเรื่องง่ายมากที่จะใช้เป็นข้อผิดพลาดเดียวกันนี้เมื่อใช้ค่าคงที่ในรหัสของคุณที่จะไม่เคยตั้งใจที่จะเป็นชนิดสตริง คำตอบของฉันมุ่งเน้นไปที่สถานการณ์ที่สอง:
ก่อนอื่น: ทำไมค่าคงที่สตริง 'วิเศษ' จึงมักจะดีกว่าค่า enum?
- ฉันชอบวิธีที่ค่าคงที่สตริงดูเทียบกับ enum - มันกะทัดรัดและ 'javascripty'
- เหมาะสมกว่าหากองค์ประกอบที่คุณใช้อยู่แล้วใช้ค่าคงที่สตริง
- การต้องนำเข้า 'ประเภท enum' เพียงเพื่อให้ได้ค่าการแจงนับอาจมีปัญหาในตัวเอง
- สิ่งที่ฉันต้องการฉันจะรวบรวมความปลอดภัยดังนั้นหากฉันเพิ่มลบค่าที่ถูกต้องจากประเภทสหภาพหรือพิมพ์ผิดมันก็ต้องให้ข้อผิดพลาดในการรวบรวม
โชคดีเมื่อคุณกำหนด:
export type FieldErrorType = 'none' | 'missing' | 'invalid'
... คุณกำลังกำหนดประเภทของสหภาพที่'missing'
จริง ๆ แล้วเป็นประเภท!
ฉันมักจะพบข้อผิดพลาด 'ไม่สามารถกำหนดได้' ถ้าฉันมีสตริงเหมือน'banana'
ใน typescript ของฉันและคอมไพเลอร์คิดว่าฉันหมายถึงมันเป็นสตริงในขณะที่ฉันต้องการให้เป็นประเภทbanana
ฉันหมายความว่ามันเป็นสตริงในขณะที่ผมอยากให้มันเป็นประเภทวิธีที่คอมไพเลอร์สามารถฉลาดขึ้นอยู่กับโครงสร้างของรหัสของคุณ
นี่เป็นตัวอย่างเมื่อฉันได้รับข้อผิดพลาดวันนี้:
// this gives me the error 'string is not assignable to type FieldErrorType'
fieldErrors: [ { fieldName: 'number', error: 'invalid' } ]
ทันทีที่ฉันพบว่า'invalid'
หรือ'banana'
อาจเป็นประเภทหรือสตริงฉันรู้ว่าฉันสามารถยืนยันสตริงเป็นประเภทนั้น โดยพื้นฐานแล้วส่งไปให้ตัวเองและบอกผู้แปลว่าฉันไม่ต้องการให้มันเป็นสตริง !
// so this gives no error, and I don't need to import the union type too
fieldErrors: [ { fieldName: 'number', error: <'invalid'> 'invalid' } ]
ดังนั้นมีอะไรผิดปกติเพียงแค่ 'หล่อ' เพื่อFieldErrorType
(หรือFruit
)
// why not do this?
fieldErrors: [ { fieldName: 'number', error: <FieldErrorType> 'invalid' } ]
มันไม่ได้รวบรวมเวลาที่ปลอดภัย:
<FieldErrorType> 'invalidddd'; // COMPILER ALLOWS THIS - NOT GOOD!
<FieldErrorType> 'dog'; // COMPILER ALLOWS THIS - NOT GOOD!
'dog' as FieldErrorType; // COMPILER ALLOWS THIS - NOT GOOD!
ทำไม? นี่คือ typescript ดังนั้น<FieldErrorType>
เป็นการยืนยันและคุณกำลังบอกคอมไพเลอร์ว่าสุนัขเป็น FieldErrorType ! และคอมไพเลอร์จะอนุญาต!
แต่ถ้าคุณทำสิ่งต่อไปนี้คอมไพเลอร์จะแปลงสตริงเป็นประเภท
<'invalid'> 'invalid'; // THIS IS OK - GOOD
<'banana'> 'banana'; // THIS IS OK - GOOD
<'invalid'> 'invalidddd'; // ERROR - GOOD
<'dog'> 'dog'; // ERROR - GOOD
แค่ระวังความผิดพลาดแบบนี้:
<'banana'> 'banan'; // PROBABLY WILL BECOME RUNTIME ERROR - YOUR OWN FAULT!
อีกวิธีในการแก้ปัญหาคือการหล่อวัตถุแม่:
คำจำกัดความของฉันมีดังนี้:
ประเภทการส่งออก FieldName = 'number' | 'expirationDate' | 'CVV'; ประเภทการส่งออก FieldError = 'none' | 'หายไป' | 'ถูกต้อง'; ประเภทการส่งออก FieldErrorType = {field: FieldName, ข้อผิดพลาด: FieldError};
สมมติว่าเราได้รับข้อผิดพลาดนี้ (ข้อผิดพลาดที่ไม่สามารถระบุได้):
fieldErrors: [ { field: 'number', error: 'invalid' } ]
เราสามารถ 'ยืนยัน' วัตถุทั้งหมดFieldErrorType
เช่นนี้:
fieldErrors: [ <FieldErrorType> { field: 'number', error: 'invalid' } ]
<'invalid'> 'invalid'
จากนั้นเราก็หลีกเลี่ยงที่จะทำ
แต่สิ่งที่เกี่ยวกับความผิดพลาด? ไม่<FieldErrorType>
เพียง แต่ยืนยันสิ่งที่อยู่ทางด้านขวาของประเภทนั้น ไม่ใช่ในกรณีนี้โชคดีที่ผู้รวบรวมจะบ่นถ้าคุณทำเช่นนี้เพราะมันฉลาดพอที่จะรู้ว่าเป็นไปไม่ได้:
fieldErrors: [ <FieldErrorType> { field: 'number', error: 'dog' } ]
export type Fruit
ใช่หรือไม่?