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> fruitString
lub fruitString as Fruit
jest 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
?