Dlaczego port Go w TypeScript 7 zepsuł narzędzia do sprawdzania kodu i narzędzia frameworkowe
Wyjaśnia, dlaczego szybszy kompilator TypeScript 7 oparty na Go dostarczany jest z niekompatybilną API, co powoduje problemy w narzędziach do sprawdzania kodu, procesie instalacji oraz aktualizacjach Vue/Svelte w całym ekosystemie.
Kompilator został wydany. API, które miało być dołączone, nie trafiło do pakietu.
Microsoft opublikował TypeScript 7.0 8 lipca 2026 roku, a nagłówek praktycznie napisał się sam: dziesięć razy szybciej. Kompilator przeniósł się z JavaScript na Go, działając na kilku wątkach i szybko przetwarzając kod, który wcześniej wymagał dwóch pełnych minut, a teraz jest przetwarzany nawet szybciej, niż zdążysz przejść do innej okna. Prawie każdy newsletter dotyczący tej wersji zawierał ten sam wykres porównawczy.
Następnie programiści rzeczywiście uruchomili polecenie npm install.
Wielu z nich otrzymało szybki format binarny, który nie funkcjonował poprawnie w zepsutym środowisku programistycznym. A problem nie był subtelny – narzędzia do sprawdzania kodu zawalały się przy prostym odczytywaniu właściwości. Menedżery pakietów odrzucały próby instalacji z powodu niezgodności zakresu zależności. Projekty Vue i Svelte w ogóle nie mogły zostać zaktualizowane. Miesiąc później większość tych problemów nadal istnieje, a żadna poprawka nie jest planowana w najbliższych wydaniach.
To właśnie ta część historii została pominięta, a to ona decyduje o tym, czy warto teraz przeprowadzać tę aktualizację.
Liczba, którą wszyscy przytaczają
Najpierw należy oddać zasługi tym, którzy je mają, ponieważ poprawa wydajności to nie tylko marketingowe sztuczki. Microsoft opublikował własne wyniki testów w komunikacie o wydaniu, a są one na tyle szczegółowe, że można je zweryfikować.
Zespół donosi o przyspieszeniach w zakresie od 8x do 12x przy pełnych budowach, a zużycie pamięci faktycznie spadło zamiast rosnąć, co jest przeciwieństwem typowej kompromisowości, jakiej można by się spodziewać. Slack poinformował Microsoft, że sprawdzanie typów w ich pipeline CI skróciło się z około siedmiu i pół minuty do nieco ponad jednej minuty, a szybkość ładowania edytora zmieniła się z ledwo użytecznej przy takiej skali na ładowanie w ciągu kilku sekund. Canva doniosło, że czas pojawienia się pierwszego błędu w edytorze zmniejszył się z około 58 sekund do mniej niż 5.
To są rzeczywiste osiągnięcia inżynieryjne, wynik rocznej ciągłej pracy. Nic z tego, co następuje, nie umniejsza ich wartości.
To była adaptacja, a nie przepisanie
Oto szczegóły techniczne, które większość doniesień pominęła, i to właśnie one wyjaśniają wszystko inne.
TypeScript 7 to adaptacja, a nie całkowite przepisanie od zera. Zespół tłumaczył istniejące pliki kompilatora, jeden po drugim, z TypeScript na Go, celowo zachowując oryginalną strukturę i logikę, aby zachowanie sprawdzania typów pozostało identyczne. Oczekuje się, że wszystko, co kompilowało się poprawnie w wersji 6.0, będzie kompilować się tak samo w wersji 7.0. Właśnie w ten sposób Microsoft zdołał wydać kompilator takiej skali bez licznych regresji w zachowaniu, co świadczy o rzeczywistej dyscyplinie podczas realizacji tej adaptacji.
Ale kompilator to w rzeczywistości dwa odrębne produkty, które dzielą jedną nazwę. Jest to plik binarny, który uruchamiamy – tsc. Jest też biblioteka, którą inne narzędzia wykorzystują jako zależność. Narzędzia do sprawdzania składni, transformatorów testów, modifikatorów kodu opartych na drzewie AST oraz sprawdzaczy szablonów nie uruchamiają tsc ani nie analizują tekstu, który on wyświetla. Zamiast tego importują TypeScript bezpośrednio, przeglądają dzięki niemu drzewo składni i pobierają informacje o typach bezpośrednio z narzędzia do sprawdzania.
Port wiernie przeniósł pierwszy produkt. Drugiego w ogóle nie przeniósł.
Sam kompilator przetrwał bez uszkodzeń. API, od którego zależą wszystkie otaczające go narzędzia, nie przetrwało wraz z nim.
Wers linijki ukrytej na dole notatki o wydaniu
Aby być sprawiedliwym wobec Microsoftu, nie chodziło tu o nic ukrytego. Jeśli przeczytasz komunikat dotyczący wersji 7.0, mniej więcej w dwóch trzecich jego długości, pod sekcją omawiającą sposób uruchamiania wersji 7.0 obok 6.0, znajdziesz zdanie, o którym wiele osób w ekosystemie rozmawiało przez cały lipiec: TypeScript 7.0 trafia do użytkowników bez API.
To znacząca luka. Microsoft twierdzi, że opracowuje nowe API i planuje udostępnić je w wersji 7.1. Według zespołu, teraz gdy prace nad portowaniem zostały zakończone, skupiają się ponownie na wprowadzaniu nowych funkcji.
Planowany rytm wydawania wersji to nowa publikacja co trzy do czterech miesięcy. Jeśli ten harmonogram się sprawdzi, wersja 7.1 powinna ukazać się około października. To wszystko, co jest obecnie znane – nie ma jeszcze potwierdzonej daty, kiedy samo nowe API będzie gotowe.
Czytaj komunikat od góry do dołu, a schemat stanie się jasny. Najpierw znajduje się tabela pokazująca, o ile szybciej działa wersja 7.0. Następnie pojawiają się entuzjastyczne komentarze od dużych firm. Dopiero potem Microsoft wspomina, niemal mimochodem, że znaczna część ekosystemu narzędzi po prostu nie może jeszcze działać w tej wersji.
Taka kolejność była celowym wyborem redakcyjnym, a nie próbą wprowadzenia kogokolwiek w błąd. To jednak także powód, dla którego tak wiele zespołów odkryło brak API na podstawie dziennika awarii w swoim terminalu, a nie z samego posta z komunikatem.
Problem 12518
Najbardziej przydatnym wynikiem pierwszego tygodnia po wprowadzeniu nie był test wydajności, lecz raport o błędzie.
Dnia, w którym nowy kompilator stał się powszechnie dostępny, ktoś aktualizujący projekt Vite plus React z wersji 6.0.3 na 7.0.2 zgłosił błąd nr 12518 dotyczący typescript-eslint, dołączając przykład jego wystąpienia. Opisano w nim dwa odrębne problemy.
Pierwszym z nich było to, że polecenie npm ci w ogóle odmawiało instalacji, ponieważ metadane pakietu typescript-eslint określały zakres zależności, poza którym znajdowała się wersja 7.0.2. Drugim problemem, który występował u tych, którzy mimo to próbowali dokonać instalacji, było to, że ESLint powodował błędy w bibliotece typescript-estree podczas kompilacji programu, ponieważ kod próbował uzyskać dostęp do właściwości w API kompilatora, której już nie istniało w tej wersji.
Opiekunowie projektu zamknęli ten błąd. Nie dlatego, że im to nie zależało, ale ponieważ nie było nic, co można by zrobić.
Czytane osobno brzmi to odrzucająco. Tak nie jest. Twórcy typescript-eslint nie mają możliwości samodzielnego naprawienia tego problemu – komponent, na którym musieliby oprzeć swoje rozwiązanie, jeszcze nie został wydany. Zamknięcie tego zgłoszenia było po prostu szczerym stwierdzeniem faktu: prawdziwa praca powinna być wykonywana w ramach TypeScript 7.1, a nie wewnątrz narzędzia lintera. Oznacza to, że najczęściej używane narzędzie do TypeScript w tym ekosystemie obecnie nie może nic zrobić ze swoją własną kompatybilnością.
Zespół ESLint otworzył odpowiednie zgłoszenie następnego dnia, potwierdził zamiar rozwiązania problemu, ale również czeka na ten sam brakujący komponent. Twórcy narzędzi Vue znajdują się w identycznej sytuacji. Wszyscy użytkownicy poniżej w łańcuchu zależności są blokowani przez tę samą niewydaną zależność.
Zasięg wpływu
Każdy pakiet, który importuje typescript i korzysta z jego wewnętrznych mechanizmów, jest narażony na to problem. Mowa konkretnie o:
- typescript-eslint wraz ze wszystkimi regułami sprawdzania kodu opartymi na tym narzędziu. Powoduje to głośny błąd, zarówno podczas instalacji, jak i przy pierwszym uruchomieniu — na pewno go zauważysz.
- ts-jest oraz wszelkie transformatory oparte na wewnętrznych wywołaniach kompilatora. W porównaniu z powyższym powodują one cichy błąd, objawiający się mylącymi błędami transformacji zamiast awarii instalacji, co jest być może gorsze, ponieważ wygląda to jak problem z konfiguracją testów, a nie niezgodność wersji.
- ts-morph oraz wszelkie niestandardowe moduły kodowe oparte na tym narzędziu. To najbardziej ryzykowna kategoria. Głęboka introspekcja typów może działać niewłaściwie w sposób pośredni, generując subtelnie błędne wyniki zamiast oczywistej awarii. Przed uruchomieniem jakichkolwiek działań niszczących w bazie kodu należy dokonać dokładnej weryfikacji.
ts-loader nadal korzystają ze starej API. Jeden z komentatorów ogłoszenia podsumował ogólne nastawienie: chęć aktualizacji istnieje, ale ponieważ większość projektów opiera się na webpacku, a jeszcze nie ma kompatybilnej API dla loaderów, wszyscy czekają na wersję 7.1.Przyjrzyj się uważnie temu, co znajduje się na tej liście. Żaden z tych narzędzi nie jest niszowy ani egzotyczny — to standardowe zestaw narzędzi typowej dzisiejszej zespołu front-end.
Sam kompilator jest stabilny. Ekosystem wokół niego — nie. To dwa odrębne stany wydania, które dzielą się tym samym numerem wersji.
Rozwiązanie Microsoftu: zainstaluj dwa kompilatory jednocześnie
Microsoft przewidział te trudności i stworzył rozwiązanie tymczasowe, zamiast pozostawiać zespoły samym im z tym radzić. Opublikowali @typescript/typescript6 — pakiet kompatybilnościowy, który zawiera wykonywalny plik tsc6 i przywraca dostęp do interfejsu API wersji 6.0. Dzięki temu stary kompilator i nowy mogą współistnieć, bez konieczności kolidowania ich nazw plików binarnych.
Powodem konieczności tego rozwiązania jest to, że narzędzia takie jak typescript-eslint rozwiązuja nazwę pakietu TypeScript poprzez zależność typu peer dependency. Dlatego zalecane rozwiązanie to użycie aliasu npm w celu przekierowania tej nazwy.
Pełna konfiguracja dwukrotnego kompilatora wygląda następująco:
{
"devDependencies": {
"@typescript/native": "npm:typescript@^7.0.2",
"typescript": "npm:@typescript/typescript6@^6.0.2"
}
}
Gdy to zostanie wdrożone, narzędzia do sprawdzania kodu, transformator testów oraz moduły kodowe będą nadal importować typescript jak zwykle i w tle otrzymywać wersję 6.0. Tymczasem uruchomienie npx tsc spowoduje użycie wersji 7.0, dzięki czemu nadal uzyskasz korzyści szybkościowe tam, gdzie są one najważniejsze — w edytorze i w procesach CI.
To rozwiązanie działa, i należy za nie podziękować: jest to dobrze zaprojektowane rozwiązanie awaryjne, szczegółowo opisane w oficjalnym komunikacie, a nie coś, co społeczność musiała odkrywać samodzielnie.
Mimo to mamy tu dwie oddzielne instalacje kompilatora znajdujące się w jednym katalogu node_modules, rozwiązane za pomocą aliasu, który każdemu nowemu członkowi zespołu trzeba będzie wyjaśnić, oraz konfigurację, którą ostatecznie będziemy musieli zmienić po faktycznym wypuszczeniu wersji 7.1. Nazywajmy to tak, jak jest: dług techniczny bez określonego terminu spłaty.
Druga pułapka – dla tych, którzy pominęli wersję 6.0
Oprócz braku API istnieje jeszcze inna pułapka czekająca na zespoły, które przeskoczyły bezpośrednio od wersji 5.x, nie przechodząc najpierw przez 6.0.
TypeScript 7.0 w pełni przyjmuje domyślne ustawienia wprowadzone przez 6.0, a każde ostrzeżenie o deprecjacji powstałe w 6.0 staje się błędem krytycznym w 7.0. Wszystko to występuje jednocześnie:
strictjest teraz włączone domyślnie.modulema teraz jako domyślną wartośćesnext.
rootDir ma jako wartość domyślną ./, zamiast być wywnioskowany automatycznie, więc jeśli plik tsconfig.json znajduje się poza katalogiem src, musisz ją ustawić wyraźnie, w przeciwnym razie kompilator błędnie oceni strukturę twojego źródła.types ma jako wartość domyślną pusty tabliczka, zamiast obejmować wszystko. Jeśli twój kod polega na globalnych zmiennych pochodzących z zainstalowanych pakietów @types, musisz albo wyraźnie wymienić te pakety, albo przywrócić dawne zachowanie za pomocą ["*"].target: es5, downlevelIteration, moduleResolution: node, baseUrl, a także tryby modułów amd, umd i systemjs. Użycie którychkolwiek z nich powoduje teraz błąd kompilacji, koniec tematu.Z tej listy zespół wyróżnia rootDir i types jako dwa zmiany, które najprawdopodobniej zaskoczą użytkowników, i to odpowiada temu, czego można się spodziewać w praktyce. Obie te sytuacje powodują napływ błędów do terminala, które sprawiają wrażenie, jakby sam kompilator był uszkodzony, zamiast wskazywać na „zmianę domyślnej wartości bez twojej wiedzy”. To właśnie taka zamieszanie skutkuje zgłaszaniem błędu kompilatora zamiast naprawy poprzez prostą edycję konfiguracji.
Istnieje również cichsza zmiana skierowana do osób zajmujących się manipulacją łańcuchami na poziomie typów. Inferencja typu literału szablonowego teraz traktuje znak taki jak emoji jako jedną jednostkę, zamiast dzielić go na dwie jednostki kodu UTF-16. Jest to bardziej intuicyjny model dla większości przypadków użycia, ale stanowi zmianę łamiącą funkcjonowanie dowolnego niestandardowego typu pomocniczego w stylu Length, który celowo liczył jednostki kodu UTF-16 zamiast widocznych znaków.
Praktyczna rada: jeśli nadal używasz wersji 5.x, nie przechodź od razu na 7.0 – najpierw zainstaluj wersję 6.0. Ta pośrednia wersja została stworzona specjalnie po to, by rozproszyć te zmiany łamiące funkcjonowanie na dwa mniejsze aktualizacje, zamiast narzucić je wszystkie jednocześnie.
Dla kogo faktycznie została stworzona ta wersja
To szczegół, nad którym warto chwilę się zatrzymać.
Spójrz na listę organizacji, które przetestowały TypeScript 7 przed jego powszechną dostępnością i dostarczyły informacje na temat tego wydarzenia: zespół VS Code, własne narzędzia Microsoftu takie jak Office, Teams, Power BI, grupy Loop i Xbox, a także Bloomberg, Canva, Figma, Google, Linear, Miro, Notion, Sentry, Slack i Vercel. Są to bazy kodu liczące miliony linii, wspierane przez dedykowane zespoły ds. infrastruktury budowania oprogramowania, które przez miesiące tworzyły wersje wstępne i zgłaszały problemy przed oficjalnym wydaniem.
Dla organizacji o takiej skali to wydanie rzeczywiście zmienia sposób wykonywania pracy, a liczby to potwierdzają. Własny zespół News Services w Microsoftu donosi o zaoszczędzeniu 400 godzin miesięcznie, które wcześniej traciły się na oczekiwanie na procesy integracji. Gdy jedna tylko kontrola typów zajmowała siedem minut, jej skrócenie o około 8 razy zmienia codzienny rytm pracy inżyniera.
Teraz porównaj to z pięcioosobowym startupem używającym Nuxt wraz z konfiguracją lintingu rozpoznającego typy. Ich sprawdzanie typów zajmowało już tylko 9 sekund. Aktualizacja pozwala im zaoszczędzić około 8 sekund, ale w zamian powoduje awarię pipeline’u lintingu, sprawdzacz szablonów Vue, który po prostu nie może działać, oraz konieczność stosowania rozwiązania typu alias w pliku package.json, którego następny pracownik zespołu będzie musiał im wyjaśnić.
Korzyści szybkościowe rosną wraz z rozmiarem bazy kodu. Natomiast problemy nie zmieniają się wcale – to stała koszt, który występuje niezależnie od tego, czy projekt składa się z dziesięciu plików, czy dziesięciu milionów.
Nic z tego nie oznacza złych intencji. To po prostu efekt optymalizacji projektu pod kątem informacji zwrotnych, które faktycznie może zaobserwować. Duże bazy kodu przedsiębiorstw były włączone do programu przeglądowego, więc ich problemy były widoczne i mierzalne na długo przed uruchomieniem. Utrzymywacze ekosystemu — głównie wolontariusze pracujący nad narzędziami do sprawdzania kodu, integracjami z IDE oraz narzędziami budowania — znajdowali się poniżej decyzji, w których nie mieli żadnego udziału, a w zamian otrzymywali jedynie rozwiązanie tymczasowe dotyczące kompatybilności oraz obietnicę, że problemy zostaną naprawione w wersji 7.1.
Ogromna baza kodu przekształca tę aktualizację w prawdziwy dar losu. Mała baza kodu natomiast płaci tę samą stałą cenę za znacznie mniejszą korzyść. To właśnie ta nierównowaga stanowi sedno całej sytuacji.
Miesiąc po ogólnej dostępności, oto mniej więcej jaka jest obecna sytuacja.
Jeśli rozważasz tę zmianę, najmniej ryzykownym rozwiązaniem jest uruchomienie 7.0 jako drugiego, nieblokującego zadania sprawdzania typów w CI obok tego, które już masz. Dzięki temu uzyskasz dokładne dane dotyczące czasu wykonywania zadań oraz większe poczucie pewności, bez konieczności uczynienia z 7.0 elementu, od którego faktycznie zależy proces budowania oprogramowania. Gdy oba zadania będą działać poprawnie przez około tydzień, możesz przejść na tę wersję.
Nie ma tu żadnej nagrody za bycie wczesnym adopterem, więc warto i tak znać dostępne opcje dostosowania: flaga --checkers kontroluje liczbę równoległych procesów sprawdzających typy, przy czym domyślnie jest to 4. Na serwerze CI o ograniczonych zasobach lepszym rozwiązaniem jest zazwyczaj obniżenie tej liczby do 1 lub 2 procesów, zamiast pozostawić ustawienie domyślne.
Odtworzenie błędu w ciągu około pięciu minut
Nic z tego nie musi być przyjmowane bezkrytycznie, i tak też nie powinno być — błąd jest na tyle mały i szybki, że można go celowo wywołać w projekcie testowym, zanim dotkniemy czegokolwiek, co naprawdę jest nam ważne.
Zacznij od nowego szkieletu Vite React-TypeScript, dodaj konfigurację ESLint rozumiejącą typy, a następnie spróbuj zainstalować nowszy kompilator przed nim:
npm create vite@latest ts7-probe -- --template react-ts
cd ts7-probe
npm install
npm install -D typescript-eslint eslint
npm install -D typescript@7
Większość ludzi napotyka problemy już podczas instalacji. Pakiet typescript-eslint deklaruje zakres zależności peer, który ogranicza wersję poniżej 6.1.0, więc npm odrzuca tę instalację bez żadnych wyjaśnień, pokazując błąd ERESOLVE zamiast łagodnego ostrzeżenia. To właściwie bardziej wyrozumiały sposób radzenia sobie z błędami.
Bardziej poważne konsekwencje występują, jeśli ignorujesz konflikt i mimo to zmuszasz do instalacji. Przy takich niepasujących pakietach uruchomienie narzędzia lint powoduje awarię w typscript-estree podczas budowania programu, z powodu dostępu do właściwości, która już nie odnosi się do żadnej wartości:
TypeError: Cannot read properties of undefined (reading 'Cjs')
at .../@typescript-eslint/typescript-estree/dist/create-program/shared.js
Zwróć uwagę, czego nie mówi ta wiadomość. Nigdy nie wspomina o TypeScript 7, nigdy nie wskazuje na niezgodność wersji, nigdy nie pisze „nieobsługiwana konfiguracja”. To surowa wewnętrzna awaria — co jest dokładnie tym problemem, który został zgłoszony w sprawie 12518: autor zgłoszenia prosił o wyraźny, czytelny dla człowieka błąd kompatybilności zamiast ścieżki wywołań, a do tej pory ta prośba pozostaje nierozpatrzona.
Następnie zastosuj wcześniej opisane rozwiązanie z użyciem aliasu i uruchom ponownie te same polecenia. Narzędzie Lint znów działa poprawnie, ponieważ w tle cicho komunikuje się z TypeScript 6.0, podczas gdy sam npx tsc nadal wykorzystuje szybszą wersję 7.0.
Gdy już tak to skonfigurowałeś, warto zmierzyć czas budowania kodu pod obiema wersjami. To właśnie ten wynik, a nie benchmarky innych osób, powinien wpłynąć na twoją decyzję — i z dużym prawdopodobieństwem będzie znacznie mniej spektakularny niż dane z VS Code, po prostu dlatego, że twoja baza kodu nie ma dwóch milionów linii.
Co z tego wyniosłem
To, co czyni TypeScript 7 osobliwym przypadkiem, to fakt, że istnieją dwa sprzeczne interpretacje tego języka, obie prawidłowe, a większość analiz wybrała tylko jedną z nich.
To poważny przykład inżynierii kompilatorów, który co tydzień zwraca rzeczywiste godziny zespołom, które traciły je na powolne procesy budowania oprogramowania. Jest to również wersja, która została wydana z tylko połową niezbędnych elementów, przy czym fakt ten został ujawniony głęboko w komunikacie, pozostawiając konsekwencje osobom odpowiedzialnym za utrzymanie oprogramowania, które nie miały wpływu na harmonogram wydania.
To, co byłoby przydatne – a czego nie widać było wyraźnie podczas premiery – to prosta zdanie na początku: ta wersja jest gotowa do użycia w procesie budowania oprogramowania, a nie w narzędziach, i oto dokładnie, co to dla Ciebie oznacza. Takie zdanie faktycznie istniało, ale było ukryte kilka sekcji dalej po wykresie benchmarków.
Wersja 7.1 ma na celu faktyczne zamknięcie tej luki. Dopóki tego nie zrobi, rozsądne podejście jest ograniczone: korzystaj z szybkości tam, gdzie nie kosztuje to nic – w swoim edytorze i w CI – oraz pozostaw każde narzędzie, które nadal importuje kompilator bezpośrednio, dokładnie takim, jakie jest.
Literatura pokrewna
- Rola mostu TypeScript 6 w drodze do natywnego kompilatora TS 7 — Dowiedz się, w jaki sposób TypeScript 6 aktualizuje domyślne konfiguracje, rozwiązywanie modułów oraz składnię importu, aby przygotować bazy kodowe na szybszy, oparty na Go kompilator TypeScript 7.