Aktualizacja bazy kodu React do TypeScript 6.0: Co psuje się najpierw
Jak bardziej restrykcyjne domyślne wartości w TypeScript 6.0, poprawka dotycząca inferencji metod, importy poddrożowe #/ oraz typy Temporal wpływają na aplikację React, plus lista kontrolna bezpiecznej aktualizacji.
Źródła: TypeScript 6.0 for React Developers: What Actually Changed
Większość aktualizacji kompilatora przebiega niezauważalnie. TypeScript 6.0 jest inny: jest to ostatnia wersja oparta na oryginalnym kompilatorze JavaScript i istnieje głównie po to, by przygotować bazy kodu na TypeScript 7 oparty na Go, dlatego oferuje mniej nowych funkcji oraz więcej zmian, które ujawniają istniejące problemy. Ten przewodnik opisuje, jak faktycznie odczuje się to w bazie kodu React, a na końcu znajduje się lista kontrolna aktualizacji. Aby dowiedzieć się, jak 6.0 wpisuje się w przejście na kompilator natywny, zobacz rolę mostu TypeScript 6 na drodze do kompilatora natywnego TS 7.
Najpierw surowsze domyślne ustawienia
TypeScript 6.0 włącza tryb ścisły jako standard, zakłada użycie modułów ES i zmienia domyślny cel na es2025. Projekty, które wyraźnie ustawiają każdą opcję, nie są dotknięte; projekty polegające na starych, bardziej luźnych ustawieniach domyślnych napotkają falę nowych błędów. W kodzie React najczęściej dotknięte są starsze komponenty: właściwości o luźnym typowaniu, funkcje obsługujące z implikowanymi parametrami any, referencje, które mogą mieć wartość null, oraz funkcja useState() bez argumentu typu. Nie są to regresje, lecz długo istniejące niejednoznaczności, które teraz są raportowane.
Cele es3 i es5 są również uznawane za przestarzałe, więc minimalnym wymogiem staje się es2015. Dla wielu aplikacji React zmiana ta ma niewielki wpływ, ponieważ Babel, SWC lub esbuild zajmują się obniżaniem poziomu składni, a tsc jedynie sprawdza typy, ale upewnij się co do tego przed ponownym przemyśleniem obsługi przeglądarek. Uruchom aktualizację na oddzielnym gałęziu z pełnym budowaniem i testami; zmiana domyślnych ustawień kompilatora w piątkowe popołudnie to pewny sposób na stracenie weekendu.
Jednolite rozumienie funkcji w stylu metod
Cichsze rozwiązanie dotyczy sytuacji, gdy funkcja jest uznawana za „wrażliwą na kontekst”, co oznacza, że typy jej parametrów muszą pochodzić z kontekstu, zanim możliwe będzie kontynuowanie inferencji. W wersji 6.0 wyrażenie function lub skrót metody jest traktowany w ten sposób tylko wtedy, gdy faktycznie używa this. Wcześniej wybór składni metody zamiast funkcji strzałkowej mógł zmienić wynik inferencji, nawet jeśli this w ogóle nie był używany. Poniższy hook łączy oba style:
// Before: inconsistent inference depending on syntax
const useCounter = (initial) => {
const [count, setCount] = useState(initial);
// this pattern used to infer differently than an arrow fn
const increment = function () {
setCount((c) => c + 1);
};
return { count, increment };
};
Wcześniej callback taki jak increment mógł być interpretowany inaczej niż odpowiednia funkcja strzałkowa, a w większych hookach ta różnica mogła doprowadzić do przeniknięcia słabszego typu do funkcji wywołujących. Teraz składnia, którą wybierzesz dla callbacki i zwracanych pomocników, już nie zmienia uzyskiwanych typów, co eliminuje mylące problemy typu „dlaczego ten callback nie został sprawdzony?”.
Czystsze importy za pomocą prefiksu #/
Importy podścieżek w Node definiują prywatne aliasy w polu imports pliku package.json, a TypeScript 6.0 obsługuje tam prefiks #/, odpowiadający aliasom korzeniowym powszechnie używanym przez narzędzia do pakowania. Mapowanie należy zadeklarować tylko raz:
{
"imports": {
"#/*": "./src/*"
}
}
Komponenty importują wtedy z korzenia projektu, zamiast liczyć segmenty ../:
// No more relative path spaghetti in deeply nested components
import { useAuth } from "#/hooks/useAuth";
import { Button } from "#/components/ui/Button";
Ponieważ alias znajduje się w package.json, a nie tylko w sekcji paths pliku tsconfig.json, Node i TypeScript rozwiązują go w identyczny sposób, bez konieczności użycia dodatkowych pluginów. Działa to tylko w trybach rozwiązywania, które czytają importy z package.json, takich jak nodenext lub bundler.
Typy tymczasowe są wbudowane
TypeScript 6.0 zawiera deklaracje dla API Temporal, które osiągnęło końcową fazę standaryzacji w ramach TC39. Zespoły tworzące interfejsy użytkownika do planowania, rezerwacji lub paneli kontrolnych mogą używać typów Temporal.PlainDate lub Temporal.ZonedDateTime bez konieczności dodawania dodatkowych pakietów, zamiast polegać na typie Date. Typy te jednak nie zapewniają wsparcia w czasie wykonywania kodu – sprawdź natywne wsparcie w wybranych przeglądarkach i wersjach Node oraz dodaj odpowiednie polyfill, jeśli to konieczne.
Czy powinieneś teraz dokonać aktualizacji?
Tak, celowo. Zespół TypeScript przedstawia wersję 6.0 jako stabilną aktualizację, ale zmiany w jej wnętrzu są rzeczywiste:
- Zbadaj plik
tsconfig.jsoni ustal konkretne wartości dla wszystkich opcji, od których zależysz. - Napraw nowe błędy wynikające z trybu strict w starszych komponentach, zamiast je tłumić za pomocą typu
any. - Upewnij się, który narzędzie realizuje funkcję downleveling oraz jaką wersję docelową wymaga.
noImplicitOverride, aby przekształcone elementy wymagały użycia słowa kluczowego override.Podsumowanie
TypeScript 6.0 nie zmieni sposobu pisania kodu w React, ale ujawnia problemy ukryte przez luźne domyślne ustawienia. Spłacenie ich teraz, według własnego harmonogramu, jest znacznie tańsze niż robienie tego później w roku, przy jednoczesnym przesiadce z wersji 6 na 7, co sprawia, że ta późniejsza zmiana staje się głównie kwestią wydajności.