Jest kilka sytuacji, które spowodują ten konkretny błąd. W przypadku PO była to wartość zdefiniowana jawnie jako ciąg . Muszę więc założyć, że może to pochodzi z listy rozwijanej, usługi internetowej lub surowego ciągu JSON.
W takim przypadku zwykła obsada <Fruit> fruitStringlub fruitString as Fruitjest jedynym rozwiązaniem (zobacz inne odpowiedzi). Nigdy nie byłbyś w stanie tego ulepszyć w czasie kompilacji. [ Edytuj: Zobacz moją drugą odpowiedź na temat<const> ]!
Jednak bardzo łatwo jest napotkać ten sam błąd, używając stałych w kodzie, które nigdy nie mają być typu string . Moja odpowiedź skupia się na tym drugim scenariuszu:
Po pierwsze: dlaczego „magiczne” stałe łańcuchowe są często lepsze niż wyliczenie?
- Podoba mi się sposób, w jaki wygląda stała łańcuchowa w porównaniu z wyliczeniem - jest kompaktowy i „javascripty”
- Ma to większy sens, jeśli składnik, którego używasz, już używa stałych łańcuchowych.
- Konieczność zaimportowania „typu wyliczenia” tylko po to, aby uzyskać wartość wyliczenia, może być sama w sobie kłopotliwa
- Cokolwiek robię, chcę, aby kompilacja była bezpieczna, więc jeśli dodam, usunę prawidłową wartość z typu unii lub błędnie ją wpiszę, MUSI to dać błąd kompilacji.
Na szczęście, kiedy zdefiniujesz:
export type FieldErrorType = 'none' | 'missing' | 'invalid'
... faktycznie definiujesz sumę typów, gdzie w 'missing'rzeczywistości jest typem!
Często napotykam błąd „nie można przypisać”, jeśli mam ciąg taki jak 'banana'w moim maszynopisie, a kompilator uważa , że mam na myśli ciąg, podczas gdy naprawdę chciałem, aby był typu banana. To, jak inteligentny może być kompilator, będzie zależeć od struktury twojego kodu.
Oto przykład, kiedy dzisiaj otrzymałem ten błąd:
// this gives me the error 'string is not assignable to type FieldErrorType'
fieldErrors: [ { fieldName: 'number', error: 'invalid' } ]
Jak tylko dowiedziałem się, że 'invalid'albo 'banana'może być albo typu lub ciągiem zdałem sobie sprawę, mogłem tylko dochodzić do tego typu ciąg . Zasadniczo rzuć to na siebie i powiedz kompilatorowi nie, nie chcę, aby to był ciąg !
// so this gives no error, and I don't need to import the union type too
fieldErrors: [ { fieldName: 'number', error: <'invalid'> 'invalid' } ]
Więc co jest złego w „przesyłaniu” do FieldErrorType(lub Fruit)
// why not do this?
fieldErrors: [ { fieldName: 'number', error: <FieldErrorType> 'invalid' } ]
Czas kompilacji nie jest bezpieczny:
<FieldErrorType> 'invalidddd'; // COMPILER ALLOWS THIS - NOT GOOD!
<FieldErrorType> 'dog'; // COMPILER ALLOWS THIS - NOT GOOD!
'dog' as FieldErrorType; // COMPILER ALLOWS THIS - NOT GOOD!
Czemu? To jest maszynopis, więc <FieldErrorType>jest to asercja i mówisz kompilatorowi, że pies to FieldErrorType ! Kompilator na to pozwoli!
ALE jeśli wykonasz następujące czynności, kompilator przekonwertuje ciąg na typ
<'invalid'> 'invalid'; // THIS IS OK - GOOD
<'banana'> 'banana'; // THIS IS OK - GOOD
<'invalid'> 'invalidddd'; // ERROR - GOOD
<'dog'> 'dog'; // ERROR - GOOD
Uważaj tylko na takie głupie literówki:
<'banana'> 'banan'; // PROBABLY WILL BECOME RUNTIME ERROR - YOUR OWN FAULT!
Innym sposobem rozwiązania problemu jest rzutowanie obiektu nadrzędnego:
Moje definicje brzmiały następująco:
typ eksportu FieldName = 'number' | „expirationDate” | „cvv”; typ eksportu FieldError = 'none' | „brakujący” | 'nieważny'; typ eksportu FieldErrorType = {field: FieldName, błąd: FieldError};
Powiedzmy, że otrzymujemy błąd z tym (błąd nie do przypisania ciągu):
fieldErrors: [ { field: 'number', error: 'invalid' } ]
Możemy `` potwierdzić '' cały obiekt w następujący sposób FieldErrorType:
fieldErrors: [ <FieldErrorType> { field: 'number', error: 'invalid' } ]
Wtedy nie musimy tego robić <'invalid'> 'invalid'.
Ale co z literówkami? Nie <FieldErrorType>tylko twierdzi, że ma prawo być tego typu. Nie w tym przypadku - na szczęście kompilator będzie narzekał, jeśli to zrobisz, ponieważ jest na tyle sprytny, aby wiedzieć, że to niemożliwe:
fieldErrors: [ <FieldErrorType> { field: 'number', error: 'dog' } ]
export type Fruit?