Any i unknown

Any i unknown w TypeScript

Poza standardowym zestawem typów TypeScript dostarcza również dwa niespotykane w standardowym JavaScript. Mianowicie any i unknown. Do czego one służą i jaka jest różnica między nimi?

Any

Typ any był obecny w TypeScript od samego początku i jak sama nazwa określa on, że dana np. zmienna może przechowywać dowolny typ danych. Dowolny. Nie tylko string, czy boolean, ale może to być też na przykład funkcja, tablica czy obiekt.

Najogólniej rzecz biorąć any cofa TypeScript do poziomu JavaScript. Zerknijmy na poniższy snippet

let x: any = 3;

x = 4;
x.prop
x();
x = { a: 5 }

const f = (a: string) => { return a };

f(x);

Deklarujemy zmienną x o type any i przypisujemy jej wartość 3. Następnie przypisujemy jej nową wartość. So far so good.

Teraz zaczynają się rzeczy ciekawe. Chcemy się dobrać do pola prop ze zmiennej x, czyli traktujemy ją jak obiekt. Jako że x jest typu any kompilator TypeScript nie będzie miał z tym najmniejszego problemu. Podobnie jest w przypadku gdy chcemy użyć x jako funkcji. Ujdzie nam to na sucho. Jak i przypisanie do x zupełnie innego typu, w tym konkretnym przypadku obiektu.

W kolejnym kroku tworzymy funkcję, która przyjmuje tekst i zwraca tekst. Przesyłamy jako argument wywołania funkcji zmienną x, która w chwili wywołania kodu jest obiektem. Ponownie kompilator nas przed tym nie ostrzeże.

Wszystkie te problemy przez typ any, który w praktyce deaktywuję sprawdzanie poprawności typów gdziekolwiek zostanie użyty.

Po co więc w ogóle go wprowadzono? Typ any jest niezwykle przydatny w pierwszym kroku migracji z JavaScript na TypeScript, który w dużym skrócie polega na zamianie rozszerzenia pliku na .ts i dodania w funkcjach typu any wszędzie tam, gdzie nie używamy typów prostych. Any następnie ma być zastępowane już konkretnymi interfejsami czy aliasami.

Poza nadużywaniem any np. nie chcę nam się tworzyć konkretnego typu w danym momencie i w kodzie pozostaje na wieki//todo: fix any, mamy jeszcze jeden, większy problem, który wkradł się w język jako taki. Mianowicie co zrobić, gdy faktycznie nie wiemy na 100% jaki typ danych otrzymamy? Gdy np. używamy zewnętrznego serwisu, który nie udostępnia typingów (możemy oczywiśćie sami zrobić dany typ, ale nie zawsze chcemy to robić). Do wersji TypeScript 3.0 używano do tego any, co deaktywowało kontrole typów w kontekście danej zmiennej.

Unknown

W wersji 3.0 TypeScript wprowadzono typ unknown, co przekłada się wprost na ‘nieznany’. Jest to typ, do którego, jak w przypadku any można przypisać cokolwiek, natomiast kompilator będzie informował nas błędem za każdym razem, gdy chcemy użyć nieznanej zmiennej bez sprawdzenia, czy np. jest ona funkcją przy wywołaniu x().

W poniższym kawałku kodu

let x: unknown = 3;

x = 4;
x.prop
x();
x = { a: 5 }

const f = (a: string) => { return a };

f(x);

Wywołania x.prop, x() oraz f(x) uraczą nas błędami kompilacji, ponieważ w danych fragmentach TypeScript nie będzie wiedział czy x.prop faktycznie istnieje, czy x jest funkcją oraz jakiego typu jest x i czy można go wykorzystać jako argument dla funkcji f.

By powyższy kod przeszedł musimy wykonać sprawdzenie typu zmiennej x, zanim zostanie użyty. Za pomocą np. typeof

let x: unknown = 3;

x = 4;
if (typeof x === 'function') {
  x();
}
x = { a: 5 }

const f = (a: string) => { return a };

if (typeof x === 'string') {
  f(x);
}

Powyższy kod się skompiluje, ponieważ gdy sprawdziliśmy typ za pomoca typeof to TypeScript to zrozumiał i danym “ifie” odpowiednio traktował daną zmienną jako funkcję czy string. Spostrzegawcze osoby zauważyły, że zniknęło x.prop, a dlatego, iż przy propertisach sprawy nieco się kompilkują i nie ma równie prostego sposobu na walidacje czy dany stan istnieje w danym obiekcie. Póki taki nie zostanie wprowadzony musimy używać typeguards, a to materiał na inny wpis.

Interesuje Cię TypeScript? Wprowadzenie do tego języka jest jednym z darmowych kursów dostępnych na kursy.clockworkjava.pl.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *