Analiza statyczna

Analiza statyczna to typ testowania, który polega na automatycznym sprawdzaniu kodu bez konieczności jego uruchamiania i pisania automatycznego testu. Prawdopodobnie zdarzyło Ci się widzieć takie testy, jeśli używasz IDE takiego jak VSCode. Sprawdzanie typu wykonywane przez TypeScript to rodzaj analizy statycznej, która może się wyświetlać jako zniekształcone wiersze pod błędami lub ostrzeżeniami.

ESLint

ESLint to narzędzie dostarczające informacji o możliwych problemach w Twojej bazie kodu. Takie problemy mogą być bezpieczne,ale same błędy lub niestandardowe zachowanie. ESLint umożliwia zastosowanie szeregu reguł sprawdzanych w Twojej bazie kodu, w tym wielu z jej „zalecanego” zestawu.

Dobrym przykładem reguły ESLint jest jej no-unsafe-final. Zapobiega to pisaniu instrukcji, które modyfikują przepływ kontroli w Twoim programie wewnątrz bloku finally. To świetna zasada, bo to nietypowy sposób pisania JavaScriptu, który może być trudny do napisania. Jest to jednak coś, co powinien być wykrywany przez prawidłowy proces weryfikacji kodu.

  try {
    const result = await complexFetchFromNetwork();
    if (!result.ok) {
      throw new Error("failed to fetch");
    }
  } finally {
    // warning - this will 'overrule' the previous exception!
    return false;
  }

W związku z tym ESLint nie zastępuje zdrowego procesu weryfikacji (i przewodnika dotyczącego stylu, który określa, jak powinna wyglądać baza kodu), ponieważ nie uwzględnia każdego nieortodoksyjnego podejścia, które deweloper może spróbować wprowadzić do bazy kodu. Przewodnik Google dla inżynierów składa się z krótkiej sekcji o tym, jak uprościć zarządzanie.

ESLint pozwala złamać regułę i oznaczyć kod jako „dozwolony”. Możesz na przykład zezwolić na poprzednią logikę, oznaczając ją w ten sposób:

  finally {
    // eslint-disable-next-line no-unsafe-finally
    return false;
  }

Jeśli stale łamiesz jakąś regułę, rozważ jej wyłączenie. Narzędzia te zachęcają do pisania kodu w określony sposób, ale Twój zespół może być przyzwyczajony do pisania kodu w inny sposób i świadomy ryzyka związanego z tym podejściem.

Wreszcie włączenie narzędzi do analizy statycznej w przypadku dużej bazy kodu może spowodować sporo nieprzydatnego szumu (i pracę do refaktoryzacji), która w przeciwnym razie działała prawidłowo. Dzięki temu łatwiej jest włączyć tę funkcję na początku cyklu życia projektu.

Wtyczki ESLint do obsługi przeglądarek

Do ESLint możesz dodać wtyczkę, która oznaczy użycie interfejsów API, które nie są powszechnie obsługiwane lub nie są obsługiwane na Twojej liście przeglądarek docelowych. Pakiet eslint-plugin-compat ostrzega Cię, gdy interfejs API może być niedostępny dla użytkowników, dzięki czemu nie musisz stale monitorować danych.

Sprawdzanie typu na potrzeby analizy statycznej

Gdy uczą się JavaScriptu, nowi programiści zwykle dowiadują się, że jest to język słabo wpisany. Oznacza to, że można zadeklarować zmienną jako jeden typ, a następnie użyć tej samej lokalizacji dla czegoś zupełnie innego. Działa to podobnie do Pythona oraz innych języków skryptów, ale w przeciwieństwie do języków skompilowanych, takich jak C/C++ czy Rust.

Ten język może być dobry na początek. Zapewne właśnie z tego powodu JavaScript zyskał tak dużą popularność. Często jest to punkt awaryjności w przypadku niektórych baz kodu, a przynajmniej taka, która sprawia, że mogą się zdarzać dezorientujące błędy. Na przykład przesłanie parametru number w miejscu, w którym był oczekiwany typ obiektu string lub typ obiektu, nieprawidłowo wpisana wartość może zostać rozpowszechniona w różnych bibliotekach, zanim ostatecznie wywoła mylącą wartość TypeError.

TypeScript

TypeScript to najbardziej popularne rozwiązanie w zakresie braku konieczności wpisywania informacji w języku JavaScript. Jest on bardzo często wykorzystywany w tym kursie. Chociaż nie jest to szkolenie o TypeScript, mogą one stanowić ważną część Twojego zestawu narzędzi, ponieważ zapewniają analizę statyczną.

Oto szybki przykład, który oczekuje, że otrzyma wywołanie zwrotne o nazwie string i wieku użytkownika number:

const callback = (name: string, age: string): void => {
  console.info(name, 'is now', age, 'years old!');
};
onBirthday(callback);

Generuje następujący błąd po uruchomieniu TypeScriptu lub nawet po najechaniu kursorem myszy w IDE:

bad.ts:4:12 - error TS2345: Argument of type '(name: string, age: string) => void' is not assignable to parameter of type '(name: string, age: number) => void'.
  Types of parameters 'age' and 'age' are incompatible.
    Type 'number' is not assignable to type 'string'.

4 onBirthday(callback);
             ~~~~~~~~

Found 1 error in bad.ts:4
Kod z poprzedniego przykładu wyświetlany w IDE z komunikatem o błędzie wyświetlanym w wyskakującym okienku.
VSCode wskazujący, że podano nieprawidłowy typ.

Ostatecznie celem korzystania z TypeScript jest zapobieganie pojawianiu się w projekcie takich błędów – wiek powinien być wartością number, a nie string. Tego rodzaju błąd może być trudny do wykrycia w innych typach testów. Dodatkowo system typów może przesyłać opinie jeszcze przed napisaniem testu. Może to ułatwić proces pisania kodu, ponieważ na wczesnym etapie dostajesz informacje o błędach typu w trakcie tworzenia oprogramowania, a nie w trakcie jego działania.

Najtrudniejszym aspektem korzystania z TypeScriptu jest jego prawidłowa konfiguracja. Każdy projekt wymaga pliku tsconfig.json, który choć jest używany głównie przez narzędzie wiersza poleceń tsc, jest też odczytywany przez IDE takie jak VSCode wraz z wieloma innymi narzędziami i narzędziami do tworzenia, w tym Vitest. Ten plik zawiera setki opcji i flag. Tu znajdziesz dobre materiały, jak go skonfigurować:

Ogólne wskazówki dotyczące TypeScriptu

Podczas konfigurowania i używania TypeScriptu za pomocą pliku tsconfig.json pamiętaj o tych kwestiach:

  • Upewnij się, że pliki źródłowe są rzeczywiście uwzględnione i sprawdzone. Jeśli plik nie zawiera błędów, prawdopodobnie nie jest sprawdzany.
  • Jawny opis typów i interfejsów w plikach .d.ts zamiast bezpośredniego opisu podczas pisania funkcji może ułatwić testowanie bazy kodu. Łatwiejsze jest pisanie próbek i „fałszywych” wersji kodu, gdy interfejsy są przejrzyste. .

Zarejestrowane przez TypeScript dowolne

Jedną z najbardziej zaawansowanych i najbardziej wartościowych opcji konfiguracji w TypeScript jest flaga noImplicitAny. Jednak często najtrudniej jest go włączyć, zwłaszcza jeśli masz już dużą bazę kodu. (Flaga noImplicitAny jest domyślnie włączona w trybie strict, ale nie jest włączona).

Ta flaga spowoduje zwrócenie błędu przez funkcję:

export function fibonacci(n) {
  if (n <= 1) {
    return 0;
  } else if (n === 2) {
    return 1;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}

Jako czytelnik jasne jest, że n powinien być liczbą, ale TypeScript nie może tego jednoznacznie potwierdzić. Jeśli używasz kodu VSCode, najedź kursorem na funkcję, aby ją opisać w następujący sposób:

function fibonacci(n: any): any

Wywołujący tę funkcję będą mogli przekazywać wartość typu any (typ, który dopuszcza dowolny inny typ), a nie tylko wartość number. Włączając flagę noImplicitAny, możesz chronić ten rodzaj kodu w trakcie programowania bez konieczności pisania obszernych testów logiki biznesowej kodu, który przekazuje nieprawidłowe typy danych w określonych miejscach.

Prostym rozwiązaniem jest oznaczenie zarówno argumentu n, jak i typu zwracanego przez funkcję fibonacci jako number.

Flaga noImplicitAny nie blokuje jednoznacznego wpisywania any w bazie kodu. Nadal możesz napisać funkcję, która akceptuje lub zwraca typ any. Zapewnia to tylko przypisanie do każdej zmiennej typu.