Poznamy dwie dość łatwe rzeczy w TS, których nieznajomość z kolei może nam napsuć sporo nerwów (z doświadczenia mówię), więc lepiej to wprowadzić jak najszybciej.
Ok, taka funkcja:
function handleRequest(url: string, method: 'GET' |'POST'){
}
Wydaje się proste. Zatem czemu błąd mamy:
let url1 = 'www.google.com';
let method1 = 'GET';
handleRequest(url1, method1); //error
Błąd to: Argument of type 'string’ is not assignable to parameter of type '”GET” | „POST”’. Ok, możemy to tak rozwiązać:
let url1 = 'www.google.com';
let method1 : 'GET' |'POST' = 'GET';
handleRequest(url1, method1); //ok
Chyba chodzi o to, że ten napis może się zmienić na coś innego. A wtedy będzie to string, zwykły string, no chyba, że określiliśmy, że method1 ma typ get|post.
Mówię chyba, bo aż takim ekspertem TSa nie jestem, w ogóle nie lubię ścisłego typowania (w każdym razie, jeszcze nie). Na potwierdzenie mojej teorii wskazuje fakt, że możemy (i powinniśmy) ten problem rozwiązać sobie przez proste const:
let url1 = 'www.google.com';
const method1 = 'GET' ;
handleRequest(url1, method1); //ok
Ok, to teraz pytanie za 100 punków, dlaczego to nie działa:
const req1 = {url: 'www.google.com', method: 'GET'} ;
handleRequest(req1.url, req1.method); //error
Ten sam błąd. Cóż, method w req1 dalej może się zmienić. Const sprawia, że po prostu nie można tam przypisać referencji do innego obiektu, nadal można jednak zmienić get na coś innego.
Ok, na to jest inny patent:
let url1 = 'www.google.com';
const method1 = 'GET' ;
handleRequest(url1, method1); //ok
const req1 = {url: 'www.google.com', method: 'GET'} as const;
handleRequest(req1.url, req1.method); //ok
I tutaj to const req1 to w zasadzie jest dla JSa, po prostu później nikt do req1 nic nowego nie przypisze. Ale to as const to oznacza, że obiekt jest niemutowalny, że to method to będzie zawsze get.
No dobra, teraz taki przykładzik:
let req2 = ["www.google.com", 'GET'];
handleRequest(...req2); //error
Tutaj mamy utility type, którego możemy użyć:
let req2 = ["www.google.com", 'GET'] as Parameters<typeof handleRequest>;
handleRequest(...req2); //ok
Tego nie ma moim zdaniem co tłumaczyć, bo to samo się opisuje. Co najwyżej warto zwrócić uwagę, że możemy zamiast as zrobić anotację:
let req2: Parameters<typeof handleRequest> = ["www.google.com", 'GET'];
handleRequest(...req2); //ok
Cóż, sam wielokrotnie denerwowałem się na TSa. Ale jak przebrniemy przez różnego rodzaju dziwactwa tego typu, to z czasem go docenimy, bo są też zalety. Wyobraźmy sobie np. że w node i express zamiast pisać te głupie bloki kodu, albo robić „MVC” przy pomocy struktury folderów z tymi blokami, po prostu sobie piszemy dekoratory z metodami jak we Flasku.
Fakt jest też taki, że można szybko pisać kod w TS, oraz wyłapywać błędy i różnego rodzaju nieścisłości szybciej i w bardziej przewidywalny sposób. Tylko nie można się odbić od tych dziwactw i zniechęcić tego typu błędami.
Więcej TSa niedługo.