Artykuł opublikowany po angielsku.
TypeScript 6's Bridge Role in the Path to a Native TS 7 Compiler
Learn how TypeScript 6 updates default configs, module resolution, and import syntax to prepare codebases for the faster, Go-based TypeScript 7 compiler.
Każdy programista, który zarządza sporym zbiorem kodu napisanego w TypeScript, zna to charakterystyczne opóźnienie. Po naciśnięciu przycisku zapisu edytor zawiesza się na kilka sekund, aż serwer językowy nadrobi zaległości. W pipeline’ach CI zgromadzają się prośby o pull requesty, ponieważ sama weryfikacja typów może trwać od pięciu do dziesięciu minut.
Programista zapisuje plik ──> [ tsc oparty na JS: przetwarzanie w pojedynczym wątku ] ──> powolna informacja zwrotna
Programista zapisuje plik ──> [ Natywny silnik TS 7: wątki równoległe ] ──> natychmiastowa informacja zwrotna
TypeScript 7 wprowadza natywnego kompilatora napisanego w Go. Przetwarza zadania na kilku wątkach, co skraca czas kompilacji o 8 do 10 razy. Jednak nie można po prostu wdrożyć wielowątkowego kompilatora natywnego do projektu, który nadal polega na ustawieniach z 2018 roku.
To jest cel TypeScript 6: służy jako punkt przejściowy. Usuwa przestarzałe problemy techniczne, odświeża nieaktualne ustawienia domyślne i zapewnia płynną kompilację projektu po pojawieniu się TypeScript 7.
Dlaczego TypeScript potrzebuje wersji mostowej?
Ponad dziesięć lat kompilator TypeScript był pisany w samym TypeScript i uruchamiany na Node.js. Dzięki temu deweloperzy JavaScript mogli łatwo przyczyniać się bezpośrednio do kodu kompilatora.
Problem polega na tym, że wykonywanie kodu w JavaScript jest jednowątkowe. Gdy bazy kodu rozrastały się do ogromnych monorepo zawierających miliony linii kodu, kompilator w końcu napotkał poważne ograniczenia wydajnościowe.
TypeScript 7 rozwiązuje ten problem poprzez równoległe wykonywanie kodu maszynowego na kilku rdzeniach CPU. Jednak kompilator równoległy wprowadza dwa wymagania dotyczące zachowania, które wcześniej nie miały znaczenia:
- Deterministyczne uporządkowanie: Nawet gdy kilka rdzeni ocenia typy jednocześnie, kompilator musi zagwarantować, że zgłaszane błędy oraz wywnioskowane typy zawsze pojawiają się w spójnej, powtarzalnej sekwencji.
- Zgodność z nowoczesnymi standardami: Kontynuowanie obsługi już dekady starej systemów modułowych, takich jak AMD, lub przestarzałych strategii rozwiązywania problemów, dodaje niepotrzebną złożoność i obciążenie kompilatorowi natywnemu.
TypeScript 6 to moment, w którym zespół wprowadza te wymagania. Skłania on programistów do stosowania aktualnych konwencji ECMAScript, aby przyszła migracja na wersję 7 nie powodowała zakłóceń.
Największe zmiany konfiguracyjne w tsconfig.json
Większość widocznych zmian wprowadzonych w TypeScript 6 znajduje się w pliku tsconfig.json. Kilka długo obowiązujących domyślnych wartości zostało zaktualizowanych, aby odzwierciedlać sposób budowania projektów w dzisiejszych warunkach.
1. strict: true jest teraz domyślnym ustawieniem
Wcześniej pusty plik tsconfig.json oznaczał, że TypeScript działał w trybie łagodnym, chyba że ręcznie ustawiono "strict": true.
Począwszy od TypeScript 6, tryb ścisły jest włączany automatycznie.
// tsconfig.json
{
„compilerOptions”: {
// W TypeScript 6 jest to teraz aktywne domyślnie
„strict”: true
}
}
Jeśli w twoim projekcie już skonfigurowano strict: true, nic się dla ciebie nie zmienia. Ale jeśli twój kod polegał na domyślnych typach any lub niezabezpieczonych wartościach null i undefined, aktualizacja natychmiast ujawni błędy typowe.
Dlaczego to ma znaczenie:
Cheker typów działa najskuteczniej, gdy informacje o typach są jawne i spójne. Luźny typowanie zmusza kompilator do radzenia sobie z nieprzewidywalnymi scenariuszami awaryjnymi, co spowalnia analizę statyczną.
2. Domyślnym celem modułu jest esnext
Historicznie TypeScript używał domyślnie starszych celów wyjściowych, takich jak ES3 lub ES5. W praktyce niemal każdy środowisko wykonawcze używane obecnie w produkcji jest „wiecznorosłe” – Node.js, Bun, Deno oraz nowoczesne przeglądarki obsługują natywne moduły ECMAScript.
W TypeScript 6 domyślną opcją module jest teraz esnext, a domyślny parametr target wskazuje na aktualną wersję ECMAScript.
// Zalecana nowoczesna konfiguracja
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler", // lub "nodenext"
"target": "es2024">
}
}
Jeśli twoja aplikacja nadal wymaga formatu CommonJS, aby działać w starszych środowiskach serwerowych, możesz samodzielnie ustawić "module": "commonjs". TypeScript po prostu nie zakłada już formatu wyjściowego typu legacy, chyba że sam o to poprosisz.
Czystsze granice modułów: Żegnaj z sztuczkami z <code>baseUrl>
Kiedyś było powszechne, że zespoły konfigurowały aliasy ścieżek w ten sposób:
// Stary wzorzec w tsconfig.json
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@components/*": ["src/components/*"],
"@services/*": ["src/services/*"]
}
}
}
W starszych wersjach TypeScript konieczne było obecność pola baseUrl, zanim w ogóle można było używać mapowań paths. To wymaganie powodowało problemy, ponieważ baseUrl umożliwiał również programistom pisanie importów bez względnego prefiksu — na przykład import { Button } from "src/components/Button" — co utrudniało odróżnienie lokalnych plików projektu od pakietów pobranych z npm.
TypeScript 6 eliminuje tę zależność: paths może teraz funkcjonować samodzielnie, bez konieczności deklaracji baseUrl. Co więcej, TypeScript 6 dodaje wrodzone wsparcie dla importów podścieżek w Node.js, zgodnie z konwencją używającą przedrostka #.
Używanie wrodzonych importów podścieżek
Zamiast polegać na specyficznych dla TypeScript aliasach, obecne projekty mogą korzystać ze standardowego pola imports w pliku package.json:
// package.json
{
"name": "my-app",
"imports": {
"#services/*": "./src/services/*.js",
"#utils/*": "./src/utils/*.js"
}
}
Z plików źródłowych można odwoływać się do tych podścieżek za pomocą standardowej składni #:
// src/api/user.ts
import { db } from "#services/database";
import { formatName } from "#utils/string";
export function getUser(id: string) {
const user = db.find(id);
return formatName(user.name);
}
Ponieważ ten mechanizm jest rozumiany przez sam Node.js i nie wymaga przepisywania na stronie kompilatora, rozwiązywanie plików staje się znacznie szybsze zarówno w TypeScript 6, jak i w nadchodzącym TypeScript 7.
Syntaks modułów dosłownych i importy typowe
Częstym problemem w kodach, które łączą kod uruchamiany w czasie wykonywania z deklaracjami typów, jest to, że importy zawierające wyłącznie informacje o typach mogą przypadkowo być traktowane jako rzeczywiste, wykonywalne importy. Gdy zaimportujesz interfejs za pomocą zwykłego polecenia import, każde narzędzie czytające ten plik musi samo ustalić, czy import zawiera rzeczywistą logikę w JavaScriptzie, czy wyłącznie informacje o typach z czasu kompilacji.
TypeScript 6 skłania zespoły do włączenia opcji verbatimModuleSyntax:
// tsconfig.json
{
"compilerOptions": {
"verbatimModuleSyntax": true
}
}
Gdy ta opcja jest włączona, zasada staje się jednoznaczna: wszystko, co stanowi wyłącznie informacje o typach, musi być importowane za pomocą słowa kluczowego import type.
// Wcześniej: Kompilator musiał sprawdzić, czy obiekty User i Order zawierają kod uruchamiany w czasie wykonywania
import { User, Order, calculateTotal } from "./billing";
// Teraz: Jasne i przewidywalne zarówno dla kompilatorów, jak i narzędzi do pakowania
import { calculateTotal } from "./billing";
import type { User, Order } from "./billing";
Dlaczego to ma znaczenie dla TypeScript 7?
Nadchodzący kompilator wielowątkowy i paralelizowany stara się przetwarzać pliki w izolacji, gdy tylko to możliwe.Instrukcja import type natychmiast informuje go, że nic w tym pliku nie wygeneruje kodu JavaScript, więc może pominąć otwieranie i analizowanie pliku ./billing.ts tylko po to, by ustalić zasady generowania kodu dla danego pliku. Ta prosta dyscyplina przyczynia się do znacznie niższego obciążenia podczas kompilacji w dużych bazach kodu.
Nowe wbudowane udogodnienia językowe
Poza domyślnymi ustawieniami konfiguracji, TypeScript 6 wprowadza szereg codziennych udogodnień, które upraszczają pisanie typowych wzorców kodu.
1. Map.getOrInsert() i Map.getOrInsertComputed()
Pomyśl o tym, jak często musiałeś pisać tę typową, powtarzalną logikę wyszukiwania w pamięci cache:
// Stary, powtarzalny sposób
const userCache = new Map<string, UserProfile>>();
function getProfile(userId: string): UserProfile {
let profile = userCache.get(userId);
if (!profile) {
profile = fetchProfileFromDatabase(userId);
userCache.set(userId, profile);
}
return profile;
}
TypeScript 6 obsługuje zaproponowaną przez TC39 metodę getOrInsertComputed, która umożliwia zastąpienie tego wzorca:
// Nowoczesny sposób w TypeScript 6
const userCache = new Map<string, UserProfile>>();
function getProfile(userId: string): UserProfile {
// Wykonuje funkcję callback tylko wtedy, gdy klucz jeszcze nie istnieje
return userCache.getOrInsertComputed(userId, () => {
return fetchProfileFromDatabase(userId);
});
}
Ta wersja jest bardziej zwięzła, unika konieczności używania zmiennej tymczasowej, która może ulec modyfikacji, i zapewnia dokładną inferencję typów przez cały czas.
2. Wbudowane typy dla RegExp.escape()
Czyszczenie znaków specjalnych przed ich użyciem w wyrażeniu regularnym wymagało wcześniej pisania własnych funkcji pomocniczych lub korzystania z pakietów od third party. TypeScript 6 dostarcza teraz wbudowane definicje typów dla RegExp.escape():
const userInput = „item.value [test]“;
// Bezpieczne ucieczkowanie znaków takich jak '.', '[', i ']'
const safePattern = RegExp.escape(userInput);
const regex = new RegExp(`^${safePattern}
Operator Software for Solar, BESS & Video | REACTAPP.TOP
TypeScript 6's Bridge Role in the Path to a Native TS 7 Compiler
);
Dzięki temu rozwiązaniu unikasz całej grupy błędów związanych z wstrzykiwaniem wyrażeń regularnych, nie dodając do swojego projektu żadnej zależności.
Przygotowanie do deterministycznego uporządkowania typów
Cichsze, ale ważne ulepszenie w TypeScript 6 to flaga stableTypeOrdering.
Aż do wersji TypeScript 5.x kolejność, w której pojawiały się elementy typu złożonego, zależała od sekwencji, w jakiej kompilator przetwarzał pliki w pamięci. Ponieważ kompilacja odbywała się na pojedynczej nitce, ta kolejność zazwyczaj pozostawała stała pomiędzy różnymi uruchomieniami.
Gdy przechodzisz na kompilator paralelizowany, taki jak ten planowany dla TypeScript 7, wątki robocze mogą kończyć przypisane im zadania za każdym razem w innej kolejności. Jeśli jeden wątek skończy prace przed drugim, typ złożony może przybrać postać string | number; jeśli uruchomisz proces budowania ponownie lub na innym komputerze, możesz otrzymać zamiast tego number | string.
Aby zapobiec nieprzewidywalnym zmianom w generowanych plikach .d.ts, TypeScript 7 stosuje wewnętrznie ścisłą, deterministyczną zasadę sortowania. TypeScript 6 umożliwia już wybór tego samego zachowania:
// tsconfig.json
{
„compilerOptions”: {
„stableTypeOrdering”: true
}
}
Jeśli twoja praca polega na utrzymywaniu pakietów otwartego oprogramowania lub dodawaniu generowanych plików deklaracji do systemu kontroli wersji, warto włączyć tę flagę i przetestować ją już dziś. Dzięki temu zapewniasz, że twoje testy typowe oraz generowane typy nie będą wykazywać bezsensownych różnic po przeniesieniu na TypeScript 7.
Praktyczna lista kontrolna migracji
Przenoszenie znaczącej bazy kodu nie musi być trudne, jeśli podejdziesz do tego etapami. Weź pod uwagę następujące priorytety:
Najpierw sprawdź każdy flag związany z strict, ponieważ jest to twoja najlepsza ochrona przed ukrytymi wartościami any oraz niezabezpieczonymi referencjami null, które mogą się pojawić przed wersją 7 — wysoki priorytet.
Usuń przestarzałe ustawienia modułów, porzucając AMD, UMD oraz tradycyjną strategię rozwiązywania problemów z modułami node — wysoki priorytet.
Włącz verbatimModuleSyntax, aby generowanie JavaScript nie zależało już w ogóle od sprawdzacza typów — średni priorytet.
Zastosuj importy poddrożowe z użyciem prefiksu #, co eliminuje potrzebę rozwiązań obejmujących specyfikę narzędzi do pakowania — średni priorytet.
Ustal rootDir wyraźnie, aby uniknąć niespodzianek w strukturze folderu wyjściowego podczas równoległych budów — niski priorytet.
Powszechne błędy, których należy unikać
Błąd 1: Wyłączanie trybu strict w celu naprawy błędów aktualizacji
Powszechnym odruchem po aktualizacji na TypeScript 6 i napotkaniu serii nowych błędów jest po prostu ustawienie "strict": false, aby integracja ciągła znów zadziałała.
To rozwiązanie może chwilowo usunąć blokadę, ale jedynie odkłada prawdziwą pracę. Poprawy wydajności w TypeScript 7 opierają się na założeniu poprawnego typowania. Zamiast całkowicie wyłączać tryb ścisły, wyłącz tymczasowo poszczególne sprawdzania – na przykład "noImplicitAny": false – i stopniowo eliminuj powstałe błędy, plik po pliku.
Błąd 2: Mieszanie importów typów i wartości
Nie łącz importów typów i wartości w jednej instrukcji po włączeniu verbatimModuleSyntax:
// Unikaj tego
import { User, UserService } from "./userService";
// Wolisz to
import { UserService } from "./userService";
import type { User } from "./userService";
Rozdzielenie ich sprawia, że jest jasne – zarówno dla czytelników, jak i kompilatora – które importy służą wyłącznie do weryfikacji typów, a które zawierają rzeczywisty kod uruchamiany w czasie wykonywania.
Kontekst ogólny: Co będzie dalej?
TypeScript 6 nie ma na celu narzucenia ci mnóstwa nowej składni do nauki. Jego prawdziwym zadaniem jest przygotowanie gruntów przed znacznie większą zmianą.
Poprzez aktualizację pliku tsconfig.json już teraz, przejście na eksplikite importy typów oraz usunięcie starego sposobu obsługi ścieżek, eliminujesz zdecydowaną większość trudności, z którymi musiałbyś się zmierzyć później. Gdy tylko zostanie wydany TypeScript 7, aktualizacja będzie polegać głównie na podniesieniu wersji pakietu i uruchomieniu nowego, natywnego kompilatora — przy czym czas budowania spadnie poniżej sekundy, a nie będzie konieczności przepisywania istniejącego kodu.
Zarezerwuj w tym tygodniu krótki czas na przejrzenie konfiguracji swojego projektu. To niewielka inwestycja, która przyniesie znaczne korzyści w dalszej perspektywie.
Jaki masz plan aktualizacji?
Czy twój zespół już pracuje w trybie ścisłym w pełni włączonym, czy nadal próbujesz uporządkować starsze ustawienia konfiguracji? Czy zacząłeś eksperymentować z importami podścieżek we własnych projektach? Podziel się swoimi pomysłami i pytaniami w komentarzach.
Powiązane materiały
- Migracja API Express do obsługiwaczy tras w Next.js App Router — Dowiedz się, jak przekształcić trasy Express, middleware oraz wzorce danych na Next.js App Router z wykorzystaniem komponentów serwerowych oraz uwzględniając kwestie implementacji.
- Spraw, by Reranking zasłużył na swoje miejsce w Twoim pipeline RAG — Drugi etap rankingu powinien dodawać przydatne informacje, zachowywać dowody oraz pokazywać mierzalne korzyści w porównaniu z bazowym podejściem opartym wyłącznie na wyszukiwaniu.
Zastępowanie Jest przez wbudowanego wykonywacza testów w Node 24 — Przykład z praktyki pokazuje, jak wbudowany wykonywacz testów w Node 24 oraz natywna obsługa TypeScript skracają czas integracji ciągłej, jednocześnie eliminując cztery zależności. Porównanie agentów AI Frontier: Astra, Flash, Fable i Mythos — Analiza wydajności najnowszych modeli GPT, Gemini i Claude w rzeczywistych zadaniach agentowych, takich jak programowanie, przeglądanie internetu i korzystanie z narzędzi, a nie tylko w testach benchmarkowych. Przepisanie TypeScript 7 na Go: co to oznacza dla bezpieczeństwa typów w React — Dowiedz się, jak kompilator TypeScript 7 oparty na Go przyspiesza proces budowania aplikacji i poprawia inferencję typów generycznych, eliminując ukryte typy any w hookach React i JSX. Kompilator TypeScript oparty na Go i wykonywanie w trybie natywnym: przewodnik migracji — Dowiedz się, jak kompilator TypeScript oparty na Go oraz wykonywanie w trybie natywnym Node.js wpłyną na projekty React i Next.js oraz co należy poprawić w pliku tsconfig już teraz.