Zwiększenie precyzji pomijania błędów przepływu
Poprawiamy tłumienie błędów przepływu, aby przypadkowo nie ukrywały błędów.
W nadchodzącym roku Flow planuje wprowadzić wiele zmian i ulepszeń w swoim systemie typów . Jedną z konsekwencji tego jest jednak to, że może być konieczne dodanie większej liczby pomijania do kodu, ponieważ Flow staje się lepszy w znajdowaniu istniejących problemów.
Może to stanowić problem, ponieważ tłumienie Flow wpływa nie tylko na pierwotny błąd, który zamierzałeś usunąć. Zmniejsza to zdolność Flow do wychwytywania błędów. Wynika to z dwóch właściwości: po pierwsze, że pomijanie przepływu może znajdować się w dowolnej części błędu typu, a po drugie, że pomijanie przepływu może pomijać każdy rodzaj błędu typu . Aby naprawić te niedociągnięcia, będziemy wymagać, aby pominięcia były umieszczane w miejscu w kodzie, w którym faktycznie występuje błąd, i aby zawierały kod błędu określający rodzaj błędu, który chcesz usunąć.
Aby zrozumieć, co to wszystko oznacza, przyjrzyjmy się naturze błędów typu Flow.
Co to jest błąd typu?
Gdy Flow napotka problem podczas sprawdzania kodu, na przykład niezgodność między dwoma typami lub nieprawidłowy dostęp do właściwości, generuje błąd, który informuje użytkownika dokładnie o tym, co jest nie tak z jego kodem. Błędy te mogą zawierać wiele różnych informacji w zależności od konkretnych okoliczności, które je spowodowały, ale najbardziej nam zależy na rodzaju błędu i lokalizacji błędu. Rodzaj błędu koduje specyficzną naturę złe zachowanie, że wykryty przepływu w kodzie, czy to coś prostego, jak przepływające zbyt wielu argumentów do funkcji, albo coś skomplikowanego jak rozprzestrzenia typ Unii. Dzięki tym informacjom Flow dokładnie określają, jakie informacje należy wyświetlić użytkownikowi, aby jak najlepiej wyjaśnić, gdzie popełniłeś błąd. Te lokalizacje tego błędu zawierają informacje o tym, gdzie znajduje się błąd w kodzie. Istnieją dwa rodzaje lokalizacji, które może zawierać błąd: lokalizacja główna (z których może być tylko jedna) i lokalizacje dodatkowe , których może być wiele lub wcale. Lokalizacja podstawowa z grubsza odpowiada lokalizacji w kodzie, w której faktycznie wystąpił błąd, podczas gdy lokalizacje drugorzędne zawierają informacje o miejscach definicji typów i wartości związanych z błędem. Na przykład:
function foo(x : number) : void {}
foo("hello");
/* error */
foo("hello");
^ Cannot call `foo` with `"hello"` bound to `x` because string [1] is incompatible with number [2].
References:
2: foo("hello");
^ [1]
1: function foo(x : number) : void {}
^ [2]
function foo(x : number) : void {}
let y : string = "hello";
foo(y);
/* error */
foo(y);
^ Cannot call `foo` with `y` bound to `x` because string [1] is incompatible with number [2].
References:
2: let y : string = "hello";
^ [1]
1: function foo(x : number) : void {}
^ [2]
Więc co jest złego w uciskach?
Cóż, ponieważ pomijanie można zastosować zarówno w lokalizacji pierwotnej, jak i drugorzędnej, umieszczenie //$FlowFixMe
komentarza powyżej definicji foo
pomija błędy w obu powyższych przykładach. Ponieważ foo
pojawia się jako drugorzędna lokalizacja w każdym błędzie, który go używa, oznaczałoby to, że jakiekolwiek użycie foo
tego skutkuje błędem, byłoby stłumione przez to jedno tłumienie, gdziekolwiek mogłoby się pojawić. Byłbyś w stanie zadzwonić foo
z dowolną liczbą argumentów dowolnego typu, a Flow nie wskazywałby na żadne błędy ani ostrzeżenia o tym wszystkim. To obniża zaufanie użytkowników do sprawdzania typu Flow i pozwala błędom, które w innym przypadku by wykrył, aby trafiły do produkcji.
Oprócz tego pomijania Flow wpływają na wszelkiego rodzaju błędy, o ile zawierają lokalizację, którą obejmuje tłumienie. Oznacza to, że wiele błędów różnego rodzaju można wyeliminować za pomocą jednego usunięcia. Aby zobaczyć niebezpieczeństwo w tym, rozważ następujący przykład:
// library file lib.js
function foo(x : number) : void {}
// impl file
const {foo} = require("lib.js");
let y : string = "hello";
// $FlowFixMe
foo(y);
Co z tym zrobimy?
Aby rozwiązać ten problem, wprowadzimy następujące zmiany:
- Wymuszaj główne lokalizacje. Zmienimy zachowanie funkcji pomijania w taki sposób, aby pomijanie dotyczyło tylko błędów umieszczonych w ich pierwotnej lokalizacji. Na przykład, zamiast pozwalać ci na pomijanie nieprawidłowego wywołania przy definicji funkcji, będziemy teraz wymagać, aby pomijanie znajdowało się w samej witrynie wywołania. W ten sposób Flow nadal będzie mógł ostrzegać Cię o innych potencjalnie nieprawidłowych wywołaniach funkcji.
- Dodaj kody błędów. Będziemy również dodawać kody błędów do naszych blokad, aby tłumiły tylko błędy określonego rodzaju. Zapobiegnie to nieoczekiwanemu tłumieniu przez supresje rodzaju błędu, którego się nie spodziewałeś.
- Standaryzuj składnię pomijania. Wcześniej akceptowalną składnię dla pomijania błędów można było konfigurować ręcznie w ramach
.flowconfig
danego projektu, pozwalając na niespójną składnię pomijania we wszystkich projektach. W ramach powyższych zmian będziemy również standaryzować składnię wygaszania; obsługuje tylko formaty$FlowFixMe[incompatible-type]
lub$FlowExpectedError[incompatible-type]
.
Wdrożenie
Zdajemy sobie sprawę, że ta zmiana może spowodować, że znaczna liczba błędów w Twoich bazach kodu stanie się nieważna, zwłaszcza jeśli miałeś zwyczaj umieszczania pomijania w kodzie biblioteki. Aby złagodzić to obciążenie, mamy kilka sugestii:
- Aby przenieść nowo nieważne wykluczenia do ich głównych lokalizacji, zalecamy połączenie narzędzi
add-comments
iremove-comments
narzędzi dostępnych w narzędziu Flow. Uruchomienie./tool remove-comments
spowoduje usunięcie wszelkich komentarzy, które nie./tool add-comments
blokują już błędów, ponieważ nie znajdują się one w lokalizacji głównej, i spowoduje umieszczenie nowych wykluczeń w nie wyłączonych lokalizacjach../tool
Skrypt można uzyskać przez klonowanie repozytorium przepływu na GitHub. - Pomijanie bez kodów błędów będzie nadal pomijać wszelkie błędy w ich lokalizacji, ale po wprowadzeniu funkcji kodów błędów możesz dodać odpowiednie kody do swojej bazy kodów w podobny sposób jak powyżej. Usunięcie wszystkich starych komentarzy i ponowne dodanie ich za pomocą
add-comments
spowoduje uwzględnienie kodu błędu w nowo dodanym komentarzu.