Po ostatnich dużych refactorach Sealiousa zauważyłem, że bardzo często zostawiam błędy w postaci “ta funkcja przyjmuje o jeden argument mniej, a go nie usunąłeś”, lub “podałem argumenty w złej kolejności”.
Sprowokowało mnie to do zastanowienia się, czy nie byłoby fajnie zacząć korzystać z TypeScripta. Dokonuje on statycznej analizy kodu i wychwytuje takie rzeczy, ale nie narzuca się za bardzo i czyni typowanie opcjonalnym.
Tak jak wspomniałem - ta myśl już zagościła w mojej głowie i uważam, że to dobry pomysł. Zrobię mały research w temacie TypeScript vs Flow w wolnej chwili i podziele się
Bez znaczenia gdzie to zostanie użyte potrzebny jest kompilator który skompliuje pliki TypeScript do regularnego JavaScriptu. Np. w @angular-cli jest watcher z webpacka który rekompiluje wszystkie zmiany w locie i działa to bardzo płynnie.
Primo, pytanie na ile można w nim korzystać z ficzerów ES6/7.
Secundo, pytanie czy to “nie narzuca się za bardzo” nie okaże się jednak za bardzo.
Chyba ja bym się wstrzymał z dodaniem tego do Sealiousa i zrealizował na tym jakiś inny, mniejszy projekt - to dałoby nam dobry ogląd sytuacji przy niewielkim koszcie jeżeli TS okazałby się jednak zbyt wkurzający.
hmm tylko wtedy wymagamy, aby cała aplikacja była odpalana za pomocą ts-node, prawda? Trochę wirusowe mi się to wydaje, chociaż i tak odpalamy apki w dockerowo izolowanym środowisku, więc who cares
Jeden z krótkich przykładów dlaczego podoba mi się TypeScript, mam sobie taki komponent i metodę add:
// heroes.component.ts
import { Hero } from "../hero";
import { HeroService } from "../hero.service";
export class HeroesComponent{
constructor(private heroService: HeroService) {}
add(name: string): void {
const newHero = new Hero();
newHero.name = name;
this.heroService.addHero(newHero).subscribe();
}
// Parametr dla `this.heroService.addHero` można zapisać krócej po prostu ` { name } `
// albo dodatkowo z użyciem słowa kluczowego `as` co znaczy mniej więcej tyle że
// mówimy do type checkera traktuj to coś `{ name }` jako obiekt innego typu - typu `Hero`
add2(name: string): void {
this.heroService.addHero({ name } as Hero).subscribe();
}
}
Automatycznie dostaniemy błąd jeżeli podamy obiekt innego typu ponieważ w serwisie ta metoda ma przyjąć zmienną typu Hero:
Oczywiście moglibyśmy zainicjonalizować obiekt Hero bezpośrednio jako argument do metody addHero komponentu heroesComponent przez new Hero(name), ale definicja modelu Hero wygląda następująco (nie mamy konstruktora):
Rozmawialiśmy trochę o tym offline z Bartkiem i napotkaliśmy jeden problem - TypeScript nie robi sprawdzania typów w trakcie runtime’u. Co powoduje, że musimy wciąż robić ręczną walidację typów, co jest dosyć upierdliwe. Znalazłem kilka alternatyw:
deno natywnie wspiera Typescript jako swój runtime, dodatkowo ma kilka innych cudownych funkcji. Warto rozważyć!
runtypes, jak nazwa wskazuje, sprawdza typy w trakcie runtime’u
Flow Runtime - korzysta ze statycznie określonych typów i dodaje runtime’owe checki
Musimy ustalić, jakie problemy chcemy rozwiązywać. Moim zdaniem są to:
Ręczne sprawdzanie typów argumentów i pisanie treści błędów w assert-ach jest upierdliwe. Aby rozwiązać ten problem potrzebujemy sprawdzania typów w trakcie runtime’u.
Patrząc na kod funkcji jest czasem trudno odgadnąć, w jakiej postaci powinna otrzymywać ona argumenty. Ten problem rozwiąże dowolna notacja określająca typy argumentów itp. Możliwość statycznej analizy ułatwiającej integrację z IDE jest mile widziana, ale moim zdaniem nie jest konieczna.
Trudno jest wykryć wszystkie niekompatybilne ze sobą wywołania funkcji, gdy robimy np. refaktor.. Tutaj statyczna analiza jest bardzo przydatna.
Z tym deno to zastanawiam się jak wygląda wydajność i jak wygląda kwestia paczek npmowych. Niby pracuje nad tym jeden z twórców Node więc to raczej poważny projekt.
W trakcie prac nad Sealpage’em zostałem przekonany do Typescripta W międzyczasie po cichu zacząłem próbę przepisywania Sealiousa na TS. Jak ktoś chciałby obczaić postęp, stworzyłem do tego brancha typescript.
Jak ktoś chce się udzielić w tym procesie (cc @piotr-ptaszynski) , zachęcam do zcheckoutowania się na ten branch i odpalenia
npm run build -- --watch
Pokaże się sterta błędów. Dużo z nich to po prostu „nie podałeś typu tego argumentu funkcji”. Zapraszam do rozwiązywania każdego z nich, nawet tych najprostszych W razie pytań pytajcie proszę tutaj. Proszę też o dawanie znać tutaj jak ktoś się będzie zabierał za jakiś moduł, żebyśmy czasem nie robili roboty 2 razy.
Ja w najbliższym czasie będę dłubał field-types - więc ochotników proszę o kierowanie swoje wysiłki na pozostałe fragmenty kodu