Strona główna / Artykuły / Skryte sukcesy TypeScript 6 oraz nawyki programistów JavaScriptu wśród doświadczonych deweloperów

Skryte sukcesy TypeScript 6 oraz nawyki programistów JavaScriptu wśród doświadczonych deweloperów

Odkryj pomijane funkcje TypeScript 6, takie jak wyraźne zarządzanie zasobami i parametry typu const, a także idiomaty JavaScriptu, na których polegają doświadczeni inżynierowie codziennie.

1228 słów

Współczesny JavaScript i TypeScript nieustannie ewoluują w sposób, który wykracza daleko poza główne funkcje i punkty z listy zmian. Obecnie istotne są dwa aspekty praktyki: mniej głośne, rzadziej promowane ulepszenia w TypeScript 6 oraz codzienne idiomaty JavaScriptu, które odróżniają prośby o integrację kodu na poziomie ekspertów od zwykłego, funkcjonalnego kodu. Oba aspekty dotyczą w rzeczywistości tej samej dyscypliny — znajomości narzędzi na tyle dobrze, by wybrać odpowiednie zamiast tego znajomego. Ten artykuł omawia oba te tematy, zaczynając od tego, co w TypeScript 6 trafiło do wersji bez większej rozgłosu, a następnie przechodząc do wzorców JavaScriptu, do których uciekają się doświadczeni inżynierowie jako standardowe rozwiązanie.

Ciche ulepszenia TypeScript 6, które warto przyjąć

Większość artykułów o TypeScript 6 skupia się wyłącznie na tym, że tryb ścisły oraz ES2025 są teraz ustawieniami domyślnymi. To rzeczywiście ważna zmiana, ale przyćmiewa ona szereg mniejszych ulepszeń, które po cichu eliminują długo stosowane rozwiązania workaround. Jeśli przeczytasz tylko nagłówki dotyczące tsconfig-default, pominiesz bardziej przydatną część tej wersji.

Oczyszczanie, o którym nie musisz pamiętać

Częstym powodem błędów jest zapomnienie zamknięcia połączenia z bazą danych lub usunięcia słuchacza. TypeScript 6 rozwiązuje ten problem dzięki wyraźnemu zarządzaniu zasobami, umożliwiając oznaczenie wartości tak, by została automatycznie usunięta po opuszczeniu zakresu.

function readUserSession() {
  using session = openSession(); // auto-disposed at scope end
  const user = session.getUser();
  return user.name;
} // session.dispose() called automatically here

To eliminuje potrzebę bloków try/finally, których jedynym zadaniem było zapewnienie oczyszczenia. Dodatek do składni jest niewielki, ale korzyści pod względem niezawodności są znaczące w przypadku plików, sokietów lub otwartych połączeń.

Typy literackie bez konieczności umieszczania as const wszędzie

Wcześniej, aby zachować typy literackie w funkcjach generycznych, trzeba było umieszczać as const w całym kodzie. TypeScript 6 wprowadza parametry typu const, które automatycznie zachowują informacje o typach literackich.

function createConfig<const T extends Record<string, unknown>>(config: T) {
  return config;
}

const config = createConfig({
  env: "production",
  features: ["auth", "billing"],
});
// config.env is "production", not string
// config.features is readonly ["auth", "billing"], not string[]

Jeśli tworzysz typowanych klientów API lub piszesz generatorów działań Redux, to eliminuje dużą część zbędnego kodu as const, którego wcześniej byłoby potrzeba.

Prawidłowe zawężanie typów wewnątrz switch (true)

Kolejna przydatna poprawka: związki dyskryminacyjne mogą teraz być prawidłowo zawężane wewnątrz instrukcji switch (true), co wcześniej zmuszało do użycia zagnieżdżonych łańcuchów if/else, aby kompilator zrozumiał typy.

function area(shape: Shape): number {
  switch (true) {
    case shape.kind === "circle":
      return Math.PI * shape.radius ** 2; // narrowed to Circle
    case shape.kind === "rectangle":
      return shape.width * shape.height; // narrowed to Rectangle
  }
}

Dzięki tej zmianie nie musisz już rezygnować z switch, aby zachować integralność zawężania typów.

Temporal otrzymuje typy pierwszej klasy

TypeScript 6 dostarcza również wbudowane typy dla API Temporal, więc nie musisz już walczyć z Date i jego specyfikami czasowych stref dzięki ręcznym asercjom typów.

const meetingStart = Temporal.Instant.from("2026-04-06T10:00:00Z");
const localTime = meetingStart.toZonedDateTimeISO("America/Toronto");

Importy podpath, które faktycznie się rozwiązują

Poprawiono również mniejszy, ale naprawdę irytujący problem: importy podpath działają teraz poprawnie, bez konieczności użycia długiej łańcuchu segmentów ścieżek względnych.

import { User } from "#/models/user.js";
// instead of ../../../models/user.js 🙃

Daniel Rosenwasser, menedżer produktu TypeScript, opisał TS6 jako celowy most prowadzący do nadchodzącego TypeScript 7 opartego na Go, co wskazuje, że nie są to eksperymentalne funkcje dodatkowe — mają zostać. Jeśli wasz zespół pracuje z pełnym stackiem JavaScript, React lub Next.js, przyjęcie tych nawyków już teraz powinno zapobiec niespodziankom po pojawieniu się TypeScript 7. Ogólnie rzecz biorąc, TypeScript 6 to nie tylko nowe domyślne ustawienia kompilatora; oferuje również lepsze zarządzanie zasobami, dokładniejszą inferencję typów oraz mniej ręcznych rozwiązań. Wypróbowanie parametrów typu using i const w następnym pull request może sprawić, że zastanowisz się, jak radziłeś sobie bez nich.

Nawyki JavaScript, które odróżniają doświadczonych programistów od pozostałych

Znajomość nowszych możliwości TypeScript to tylko połowa obrazu. Druga połowa dotyczy tego, jak sam JavaScript jest pisany na co dzień. Gdy prośba o zmianę od doświadczonego inżyniera jest bardziej czytelna niż te od innych, rzadko chodzi o pomysłowość — chodzi o spójny zestaw nawyków stosowanych bez wahania.

Łańcuchowanie opcjonalne i łączenie wartości nullowych

Zamiast łańcuchów typu user && user.profile && user.profile.name, doświadczeni programiści korzystają z łańcuchowania opcjonalnego połączonego z łączeniem wartości nullowych.

const displayName = user?.profile?.name ?? 'Guest';

Jest zwięzłe, chroni przed brakującymi wartościami i nie powoduje błędów podczas refaktoryzacji otaczającego kodu.

Destrukcyjne rozpakowywanie z wartościami domyślnymi

Destrukcyjne rozpakowywanie właściwości, odpowiedzi API oraz argumentów funkcji — z wbudowanymi rozsądnymi wartościami domyślnymi — jest w tym poziomie czymś naturalnym.

function createUser({ name, role = 'member', isActive = true }) {
  return { name, role, isActive };
}

Takie postępowanie dokumentuje oczekiwany kształt danych bezpośrednio w sygnaturze funkcji.

Async/Await zamiast łańcuchowych obietnic

Łańcuchowanie .then().then().catch() nadal działa, ale nie radzi sobie dobrze wraz ze wzrostem złożoności logiki. Porównaj to z wersją używającą async/await:

async function fetchOrders(userId) {
  try {
    const res = await fetch(`/api/orders/${userId}`);
    if (!res.ok) throw new Error('Failed to fetch orders');
    return await res.json();
  } catch (err) {
    console.error('Order fetch failed:', err);
    throw err;
  }
}

Wynik jest czytelny od góry do dołu, co ułatwia debugowanie i testowanie.

Metody tablic zamiast ręcznych pętli

Użycie metod map, filter, reduce i find zastępuje większość ręcznie pisanych pętli for.

const activeAdmins = users
  .filter((u) => u.isActive && u.role === 'admin')
  .map((u) => u.email);

To oznacza mniej zmiennych, które mogą ulec zmianie, oraz mniej błędów typu „off-by-one”.

Typy pomocnicze zamiast powtarzanych interfejsów

Zamiast ponownie definiować niemal identyczne interfejsy, doświadczeni programiści używających TypeScripta polegają na typach pomocniczych takich jak Partial, Pick i Omit.

type UserFormInput = Pick<User, 'name' | 'email'> & Partial<Pick<User, 'phone'>>;

Dzięki temu istnieje jedno źródło prawdy, więc zmiany w schemacie wymagają aktualizacji w mniejszej liczbie miejsc.

Hooks i kompozycja w React

W dojrzałych kodach React często spotyka się niestandardowe hooks, które wyodrębniają i zamykają logikę w sobie.

function useDebouncedValue(value, delay = 300) {
  const [debounced, setDebounced] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debounced;
}

Taki hook umożliwia ponowne użycie i testowanie podstawowej logiki niezależnie od konkretnej komponenty.

Zorganizowane zarządzanie stanem

W zakresie zarządzania stanem wiele doświadczonych zespołów preferuje elementy Redux Toolkit nad ręcznie pisanymi reduktorami opartymi na instrukcjach switch, ponieważ RTK zmniejsza ilość kodu powtarzalnego i dzięki Immer zapewnia bezpłatną niezmienność danych.

Jak słynnie zauważył Douglas Crockford, JavaScript składa się z „dobrych i złych elementów” — ta sama elastyczność, która sprawia, że język jest potężny, może również prowadzić do zamieszania. Umiejętność wyboru tych elementów, na które się oprzeć, odróżnia doświadczonych inżynierów od tych, którzy wciąż szukają swojej drogi.

Kilka prostych zasad łączy to wszystko w całość: priorytet należy dać czytelności nad pomysłowością, niech system typów TypeScript przejmuje obowiązek dokumentacji zamiast komentarzy, a funkcjonalność należy budować na małych, składanych funkcjach zamiast dużych, monolitycznych.

Literatura pokrewna