Oto, co mam w fruit.ts
export type Fruit = "Orange" | "Apple" | "Banana"
Teraz importuję fruit.ts w innym pliku maszynopisu. Oto co mam
myString:string = "Banana";
myFruit:Fruit = myString;
Kiedy robię
myFruit = myString;
Pojawia się błąd:
Nie można przypisać typu „string” do typu „Orange” | „Jabłko” | "Banan"'
Jak mogę przypisać ciąg do zmiennej typu niestandardowego Fruit?
javascript
typescript
angular
user6123723
źródło
źródło
export type Fruit
?Odpowiedzi:
Musisz go przesłać :
Zauważ również, że używając literałów łańcuchowych , musisz użyć tylko jednego
|
Edytować
Jak wspomniano w drugiej odpowiedzi @Simon_Weaver, teraz można to potwierdzić
const
:źródło
const myFruit: Fruit = "Banana"
wystarczy.let myFruit:Fruit = "Apple" let something:string = myFruit as string
To daje mi błąd: Konwersja typu „Fruit” na typ „string” może być błędem.as string
części. Wypróbowałem twój kod na placu zabaw i nie ma błędów.const myString: string = 'Bananaaa';
, nie otrzymuję błędów kompilacji z powodu rzutowania ... czy nie ma sposobu, aby to zrobić podczas sprawdzania ciągu?Typescript
3.4
wprowadza nową asercję „const”Możesz teraz zapobiec „rozszerzaniu” typów dosłownych (np.
'orange'
Lub'red'
) w celu wpisaniastring
za pomocą tak zwanegoconst
potwierdzenia.Będziesz mógł:
I wtedy już się nie zmieni
string
- co jest źródłem problemu w pytaniu.źródło
let fruit = 'orange' as const;
następująca przy przestrzeganiu reguły asercji typu bez kątownikaKiedy to robisz:
... tworzysz nazwany typ,
Fruit
który może zawierać tylko literały"Orange"
,"Apple"
i"Banana"
. Ten typ rozszerza sięString
, dlatego można go przypisaćString
. JednakString
NIE rozszerza się"Orange" | "Apple" | "Banana"
, więc nie można go do niego przypisać.String
jest mniej szczegółowy . Może to być dowolny ciąg .Kiedy to robisz:
...to działa. Czemu? Ponieważ rzeczywisty typ od
myString
w tym przykładzie"Banana"
. Tak,"Banana"
to jest typ . Jest rozszerzany,String
więc można go przypisać doString
. Ponadto typ rozszerza Union Type, gdy rozszerza którykolwiek z jego składników. W tym przypadku"Banana"
typ rozszerza się,"Orange" | "Apple" | "Banana"
ponieważ przedłuża jeden z jego składników. Dlatego"Banana"
można go przypisać do"Orange" | "Apple" | "Banana"
lubFruit
.źródło
<'Banana'> 'Banana'
a to „rzuci”"Banana"
strunę"Banana"
na typ !!!<const> 'Banana'
co jest lepsze :-)Widzę, że jest to trochę stare, ale tutaj może być lepsze rozwiązanie.
Jeśli chcesz, aby ciąg znaków był zgodny tylko z określonymi wartościami, możesz użyć wyliczeń .
Na przykład:
Teraz wiesz, że bez względu na wszystko, myFruit zawsze będzie ciągiem „Banan” (lub jakąkolwiek inną wyliczalną wartością, którą wybierzesz). Jest to przydatne w wielu przypadkach, niezależnie od tego, czy chodzi o grupowanie podobnych wartości, jak to, czy mapowanie przyjaznych dla użytkownika wartości na wartości przyjazne dla maszyny, a wszystko to przy wymuszaniu i ograniczaniu wartości, na które zezwala kompilator.
źródło
let myFruit: Fruit = "Banana"
.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
lubfruitString 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?
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ł typubanana
. 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:
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 !Więc co jest złego w „przesyłaniu” do
FieldErrorType
(lubFruit
)Czas kompilacji nie jest bezpieczny:
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
Uważaj tylko na takie głupie literówki:
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):
Możemy `` potwierdzić '' cały obiekt w następujący sposób
FieldErrorType
: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:źródło
Wszystkie powyższe odpowiedzi są prawidłowe, jednak w niektórych przypadkach typ literału ciągu jest częścią innego złożonego typu. Rozważmy następujący przykład:
Masz wiele rozwiązań, aby to naprawić. Każde rozwiązanie jest ważne i ma swoje własne przypadki użycia.
1) Pierwszym rozwiązaniem jest zdefiniowanie typu rozmiaru i wyeksportowanie go z pliku foo.ts. Jest to dobre, jeśli musisz samodzielnie pracować z parametrem rozmiaru. Na przykład masz funkcję, która akceptuje lub zwraca parametr typu size i chcesz go wpisać.
2) Drugą opcją jest po prostu rzutowanie go na typ ToolbarTheme. W takim przypadku nie musisz ujawniać wewnętrznej części ToolbarTheme, jeśli nie potrzebujesz.
źródło
Jeśli
dropdownvalue[]
na przykład rzutujesz na a podczas mockowania danych, utwórz go jako tablicę obiektów z właściwościami value i wyświetlania.przykład :
źródło
Miałem ten sam problem, wprowadziłem poniżej zmiany i problem został rozwiązany.
Otwórz plik watchQueryOptions.d.ts
Zmień typ zapytania na dowolny zamiast DocumentNode , taki sam dla mutacji
Przed:
Po:
źródło