TypeScript 6 i 7: Mądrzejsza inferencja, a następnie przepisanie w oparciu o Go
Dowiedz się, w jaki sposób TypeScript 6 naprawił braki w domyślnej inferencji kluczy oraz zmodernizował wartości domyślne, przygotowując grunt pod całkowitą przebudowę kompilatora w TypeScript 7 przy użyciu języka Go.
Ostatnio TypeScript rozwija się na dwóch różnych frontach, a razem tworzą one jedną historię: język staje się zarówno inteligentniejszy, jak i szybszy. TypeScript 6, który został wydany jako ostateczna wersja napisana przy użyciu tradycyjnego kompilatora opartego na JavaScript przed dużą zmianą architektoniczną, skupił się na naprawieniu dawno istniejących problemów z inferencją oraz modernizacji domyślnych ustawień. Następnie TypeScript 7 podjął bardziej radykalny krok i przepisał sam kompilator w języku Go, dążąc do maksymalnej szybkości zamiast do nowej składni. Porównanie obu wersji pokazuje, jak cały zestaw narzędzi doszedł do swojego obecnego stanu — najpierw stając się bardziej dokładny, a potem znacznie szybszy.
Mądrzejsza inferencja w TypeScript 6
Każdy, kto wpisał skrót metody, a następnie patrzył, jak parametr cichо zamienia się w any, wie, jak irytujące mogą być stare zasady inferencji w TypeScript. TypeScript 6 rozwiązuje ten problem oraz kilka innych luk w inferencji, które od lat zmuszają programistów do poszukiwania odpowiedzi.
Wcześniej każda funkcja, która wewnętrznie odwoływała się do this, była traktowana jako „wrażliwa na kontekst”, co oznaczało, że kompilator całkowicie pomijał inferencję typu parametru — nawet w przypadkach, gdy this w ogóle nie był używany wewnątrz ciała funkcji:
// Old behavior: 'user' silently became 'any'
const handlers = {
onSave(user) {
console.log(user.name); // no autocomplete, no error
},
};
W TypeScript 6 kompilator traktuje funkcję jako wrażliwą na kontekst tylko wtedy, gdy w jej wnętrzu rzeczywiście używane jest this. Jeśli tak nie jest, aktywuje się standardowe wnioskowanie i parametr otrzymuje swoją oczekiwaną typizację, zamiast przyjmować wartość any:
// TypeScript 6: 'user' is correctly inferred from context
const handlers: Handlers = {
onSave(user) {
console.log(user.name); // fully typed
},
};
Wydaje się to małą korektą techniczną, ale ma ogromny wpływ na codzienną pracę nad kodem, szczególnie w projektach React i Next.js, gdzie metody obiektów oraz obsługi zdarzeń występują wszędzie.
TypeScript 6 wprowadza również pełne wsparcie dla deklaracji using, które formalizują zarządzanie zasobami. Zamiast ręcznie umieszczać logikę czyszczenia w bloku try/finally, można pozwolić kompilatorowi automatycznie zajmować się zwalnianiem zasobów po wyjściu wartości poza zakres dostępu:
function readConfig() {
using file = openFile("./config.json"); // auto-disposed at scope end
return JSON.parse(file.read());
}
Importy podścieżek również stają się prostsze. Przedrostek #/ działa teraz poprzez pole imports, co pozwala uniknąć długich łańcuchów względnych ścieżek ../../../:
{
"imports": {
"#/*": "./src/*"
}
}
import { formatCurrency } from "#/utils/currency";
// instead of: import { formatCurrency } from "../../../utils/currency";
Kilka ustawień domyślnych również uległo zmianie. Opcja target teraz ma za domyślną wartość ES2023 zamiast starszego standardu ES3, module ma za domyślną wartość ESNext, a moduleResolution ma za domyślną wartość bundler. Opcja types również ma za domyślną wartość pusty tablicę, co zapobiega automatycznemu skanowaniu i ładowaniu przez TypeScript każdego pakietu @types, który może znaleźć. Samo to ostatnie zmiany przyczyniły się, według Microsoftu, do poprawy czasu kompilacji o 20 do 50 procent, co sprawia, że warto przejrzeć plik tsconfig.json, nawet jeśli nie masz zamiaru korzystać z nowych funkcji języka.
Podsumowując, rekomendacje dotyczące TypeScript 6 to: przeprowadź audyt wszystkich obiektów w twojej bazie kodu, które zawierają wiele metod, ponieważ mogą one otrzymać automatyczne ulepszenia bezpieczeństwa typów za darmo; używaj klauzuli using tam, gdzie pracujesz z plikami, połączeniami lub timerami wymagającymi czyszczenia; nie przyjmuj po cichu nowych domyślnych ustawień kompilatora – ustaw je wyraźnie w pliku tsconfig.json, aby twoje intencje były jasne; oczekuj również, że definicje typów dostarczane przez frameworki i biblioteki takie jak React, Redux oraz narzędzia Tailwind nadrobią te zmiany w ciągu najbliższych tygodni. TypeScript 6 nie jest wydaniem tymczasowym – znacząco zmniejsza liczbę niespodzianek związanych z domyślnymi wnioskami typów, z którymi spotykamy się na co dzień, a to samo w sobie jest wystarczającym powodem do aktualizacji.
Powrót od zera w TypeScript 7
Podczas gdy TypeScript 6 udoskonalił sposób, w jaki kompilator rozumie typy, TypeScript 7 zmierza w kierunku czegoś bardziej fundamentalnego: szybkości działania całego zestawu narzędzi. Microsoft całkowicie przepisał kompilator, usługę językową oraz powiązane narzędzia w języku Go, zastępując tym samym własną implementację w JavaScriptu, która przez lata napędzała TypeScript. Nie jest to zwykłe podniesienie wersji – opisuje się je jako największą zmianę pod względem wydajności w historii tego języka.
Każdy, kto kiedykolwiek wpatrywał się w ikonkę ładowania edytora, czekając na pojawienie się błędu typu, rozpozna dokładnie ten problem, który ma na celu rozwiązanie ta nowa wersja.
Ponieważ zespół przejął istniejącą logikę kompilatora zamiast budować reguły sprawdzania typów od zera, kompatybilność z istniejącym kodem pozostała w dużej mierze nienaruszona podczas całej transformacji.
Opublikowane przez samego Microsofta testy wydajności dają pojęcie o skali ulepszeń. W bazie kodu VS Code liczącej około 1,5 miliona linii, pełne skompilowanie, które wcześniej trwało około 125 sekund, teraz zajmuje zaledwie około 10 sekund. Czas pojawienia się pierwszego błędu typu w edytorze zmniejszył się z około 17 sekund do nieco ponad 1,5 sekundy. Zużycie pamięci spadło o około 18 procent, a awarie w serwerze językowym zmniejszyły się o ponad 60 procent. To również nie są czysto syntetyczne liczby — firmy takie jak Slack, Figma, Google, Notion i Vercel przetestowały nowy kompilator w rzeczywistych projektach produkcyjnych przed jego wprowadzeniem i stwierdziły, że osiągnięcia te utrzymywały się poza kontrolowanymi testami wydajności.
Dla zespołów pracujących z React i Next.js oznacza to konkretne korzyści w codziennej pracy. W dużym monorepo oczekiwanie na zakończenie procesu tsc w celu wykrycia niezgodności typów mogło wcześniej trwać kilka sekund; ten czas oczekiwania znacznie się skraca dzięki kompilatorowi opartemu na Go:
// Before: waiting on tsc to catch this in a large monorepo could take seconds
interface UserCardProps {
name: string;
avatarUrl?: string;
onSelect: (userId: string) => void;
}
function UserCard({ name, avatarUrl, onSelect }: UserCardProps) {
// With TS7's native checker, this feedback loop is nearly instant
return (
<button onClick={() => onSelect(name)} className="rounded-lg p-2 hover:bg-slate-100">
{avatarUrl && <img src={avatarUrl} alt={name} className="h-8 w-8 rounded-full" />}
<span>{name}</span>
</button>
);
}
Wielkie aplikacje Next.js składające się z setek komponentów nie traktują już weryfikacji typów jako wąskiego gardła w procesie CI, jak to było wcześniej. Projekty budowane z użyciem zaawansowanych typów ogólnych, takie jak te łączące Tailwind i Redux, charakteryzują się znacznie szybszym budowaniem elementów po kolei. Funkcja autodopasowywania w edytorze w dużych monorepo również działa znacznie sprawniej.
Zanim przeprowadzisz aktualizację, istnieje kilka kwestii, na które warto zwrócić uwagę. Tryb ścisły jest teraz domyślny, więc wcześniej luźne bazy kodu mogą wykazywać nowe błędy. Starsze cele kompilacji, takie jak es5, wraz z dawniejszymi ustawieniami rozwiązywania modułów, nie są już jedynie ostrzeżeniami — traktuje się je jako poważne błędy. Ponadto, ponieważ API programistyczne w tej wersji jest tylko częściowo stabilne, każda platforma lub narzędzie, które od niego bezpośrednio zależy, powinno poczekać do wersji TypeScript 7.1 przed przeprowadzeniem aktualizacji.
Wszystko to nie wymaga nowej składni ani zasadniczo innej gramatyki — TypeScript 7 powstał głównie w odpowiedzi na od dekady słyszane skargi na wydajność kompilatora. Jeśli wasz zespół pracuje z dużym kodem w React lub Next.js, to właśnie ta wersja sprawia, że tsc przestaje być czymś, z czym trzeba walczyć. Podobnie jak przy każdej większej zmianie infrastrukturalnej, warto najpierw przetestować ją na gałęzi pobocznej; waszy pipeline CI podziękuje wam za taką ostrożność.
Literatura pokrewna
- Przepisanie TypeScript 7 na język Go: co to oznacza dla bezpieczeństwa typów w React — Dowiedzcie się, jak kompilator TypeScript 7 oparty na języku Go przyspiesza procesy budowania i poprawia inferencję typów ogólnych, eliminując ukryte typy
anyw hookach React i JSX.