Polski

Odkryj moc asercji const w TypeScript dla niezmiennego wnioskowania typów, zwiększając bezpieczeństwo i przewidywalność kodu. Dowiedz się, jak ich używać na przykładach.

Asercje const w TypeScript: Niezmienne wnioskowanie typów dla solidnego kodu

TypeScript, nadzbiór JavaScriptu, wprowadza statyczne typowanie do dynamicznego świata tworzenia aplikacji internetowych. Jedną z jego potężnych funkcji jest wnioskowanie typów, gdzie kompilator automatycznie dedukuje typ zmiennej. Asercje const, wprowadzone w TypeScript 3.4, przenoszą wnioskowanie typów o krok dalej, umożliwiając wymuszanie niezmienności i tworzenie bardziej solidnego i przewidywalnego kodu.

Czym są asercje const?

Asercje const to sposób, aby poinformować kompilator TypeScript, że zamierzasz, aby dana wartość była niezmienna. Stosuje się je za pomocą składni as const po wartości literałowej lub wyrażeniu. Instruuje to kompilator, aby wywnioskował jak najwęższy możliwy (literałowy) typ dla wyrażenia i oznaczył wszystkie właściwości jako readonly.

W istocie, asercje const zapewniają silniejszy poziom bezpieczeństwa typów niż samo zadeklarowanie zmiennej za pomocą const. Podczas gdy const zapobiega ponownemu przypisaniu samej zmiennej, nie zapobiega modyfikacji obiektu lub tablicy, do której zmienna się odnosi. Asercje const zapobiegają również modyfikacji właściwości obiektu.

Korzyści z używania asercji const

Praktyczne przykłady

Przykład 1: Podstawowe użycie z literałem

Bez asercji const, TypeScript wnioskuje typ message jako string:


const message = "Hello, World!"; // Typ: string

Z asercją const, TypeScript wnioskuje typ jako literał ciągu znaków "Hello, World!":


const message = "Hello, World!" as const; // Typ: "Hello, World!"

Pozwala to na użycie typu literału ciągu znaków w bardziej precyzyjnych definicjach typów i porównaniach.

Przykład 2: Użycie asercji const z tablicami

Rozważmy tablicę kolorów:


const colors = ["red", "green", "blue"]; // Typ: string[]

Mimo że tablica jest zadeklarowana za pomocą const, nadal można modyfikować jej elementy:


colors[0] = "purple"; // Brak błędu
console.log(colors); // Wynik: ["purple", "green", "blue"]

Dodając asercję const, TypeScript wnioskuje typ tablicy jako krotkę ciągów znaków tylko do odczytu:


const colors = ["red", "green", "blue"] as const; // Typ: readonly ["red", "green", "blue"]

Teraz próba modyfikacji tablicy spowoduje błąd TypeScript:


// colors[0] = "purple"; // Błąd: Sygnatura indeksu w typie 'readonly ["red", "green", "blue"]' pozwala tylko na odczyt.

Zapewnia to, że tablica colors pozostaje niezmienna.

Przykład 3: Użycie asercji const z obiektami

Podobnie jak tablice, obiekty również można uczynić niezmiennymi za pomocą asercji const:


const person = {
  name: "Alice",
  age: 30,
}; // Typ: { name: string; age: number; }

Nawet z const, wciąż można modyfikować właściwości obiektu person:


person.age = 31; // Brak błędu
console.log(person); // Wynik: { name: "Alice", age: 31 }

Dodanie asercji const sprawia, że właściwości obiektu stają się readonly:


const person = {
  name: "Alice",
  age: 30,
} as const; // Typ: { readonly name: "Alice"; readonly age: 30; }

Teraz próba modyfikacji obiektu spowoduje błąd TypeScript:


// person.age = 31; // Błąd: Nie można przypisać do 'age', ponieważ jest to właściwość tylko do odczytu.

Przykład 4: Użycie asercji const z zagnieżdżonymi obiektami i tablicami

Asercje const można stosować do zagnieżdżonych obiektów i tablic, aby tworzyć głęboko niezmienne struktury danych. Rozważmy następujący przykład:


const config = {
  apiUrl: "https://api.example.com",
  endpoints: {
    users: "/users",
    products: "/products",
  },
  supportedLanguages: ["en", "fr", "de"],
} as const;

// Typ:
// {
//   readonly apiUrl: "https://api.example.com";
//   readonly endpoints: {
//     readonly users: "/users";
//     readonly products: "/products";
//   };
//   readonly supportedLanguages: readonly ["en", "fr", "de"];
// }

W tym przykładzie obiekt config, jego zagnieżdżony obiekt endpoints oraz tablica supportedLanguages są oznaczone jako readonly. Gwarantuje to, że żadna część konfiguracji nie zostanie przypadkowo zmodyfikowana w czasie wykonania.

Przykład 5: Asercje const z typami zwracanymi przez funkcje

Możesz użyć asercji const, aby upewnić się, że funkcja zwraca niezmienną wartość. Jest to szczególnie przydatne przy tworzeniu funkcji pomocniczych, które nie powinny modyfikować swoich danych wejściowych ani tworzyć modyfikowalnych danych wyjściowych.


function createImmutableArray(items: T[]): readonly T[] {
  return [...items] as const;
}

const numbers = [1, 2, 3];
const immutableNumbers = createImmutableArray(numbers);

// Typ immutableNumbers: readonly [1, 2, 3]

// immutableNumbers[0] = 4; // Błąd: Sygnatura indeksu w typie 'readonly [1, 2, 3]' pozwala tylko na odczyt.

Przypadki użycia i scenariusze

Zarządzanie konfiguracją

Asercje const są idealne do zarządzania konfiguracją aplikacji. Deklarując obiekty konfiguracyjne z as const, możesz zapewnić, że konfiguracja pozostanie spójna przez cały cykl życia aplikacji. Zapobiega to przypadkowym modyfikacjom, które mogłyby prowadzić do nieoczekiwanego zachowania.


const appConfig = {
  appName: "My Application",
  version: "1.0.0",
  apiEndpoint: "https://api.example.com",
} as const;

Definiowanie stałych

Asercje const są również przydatne do definiowania stałych o określonych typach literałowych. Może to poprawić bezpieczeństwo typów i czytelność kodu.


const HTTP_STATUS_OK = 200 as const; // Typ: 200
const HTTP_STATUS_NOT_FOUND = 404 as const; // Typ: 404

Praca z Reduxem lub innymi bibliotekami do zarządzania stanem

W bibliotekach do zarządzania stanem, takich jak Redux, niezmienność jest podstawową zasadą. Asercje const mogą pomóc w egzekwowaniu niezmienności w reducerach i kreatorach akcji, zapobiegając przypadkowym mutacjom stanu.


// Przykładowy reducer Redux

interface State {
  readonly count: number;
}

const initialState: State = { count: 0 } as const;

function reducer(state: State = initialState, action: { type: string }): State {
  switch (action.type) {
    default:
      return state;
  }
}

Internacjonalizacja (i18n)

Podczas pracy z internacjonalizacją często masz do czynienia z zestawem obsługiwanych języków i odpowiadających im kodów lokalnych. Asercje const mogą zapewnić, że ten zestaw pozostanie niezmienny, zapobiegając przypadkowym dodaniom lub modyfikacjom, które mogłyby zepsuć implementację i18n. Wyobraź sobie na przykład obsługę języka angielskiego (en), francuskiego (fr), niemieckiego (de), hiszpańskiego (es) i japońskiego (ja):


const supportedLanguages = ["en", "fr", "de", "es", "ja"] as const;

type SupportedLanguage = typeof supportedLanguages[number]; // Typ: "en" | "fr" | "de" | "es" | "ja"

function greet(language: SupportedLanguage) {
  switch (language) {
    case "en":
      return "Hello!";
    case "fr":
      return "Bonjour!";
    case "de":
      return "Guten Tag!";
    case "es":
      return "¡Hola!";
    case "ja":
      return "こんにちは!";
    default:
      return "Greeting not available for this language.";
  }
}

Ograniczenia i uwagi

Alternatywy dla asercji const

Chociaż asercje const są potężnym narzędziem do wymuszania niezmienności, istnieją inne podejścia, które można rozważyć:

Dobre praktyki

Podsumowanie

Asercje const w TypeScript są cennym narzędziem do wymuszania niezmienności i poprawy bezpieczeństwa typów w kodzie. Używając as const, możesz poinstruować kompilator, aby wywnioskował jak najwęższy możliwy typ dla wartości i oznaczył wszystkie jej właściwości jako readonly. Może to pomóc w zapobieganiu przypadkowym modyfikacjom, poprawić przewidywalność kodu i odblokować bardziej precyzyjne sprawdzanie typów. Chociaż asercje const mają pewne ograniczenia, stanowią potężny dodatek do języka TypeScript i mogą znacznie zwiększyć solidność Twoich aplikacji.

Strategicznie włączając asercje const do swoich projektów TypeScript, możesz pisać bardziej niezawodny, łatwiejszy w utrzymaniu i przewidywalny kod. Wykorzystaj moc niezmiennego wnioskowania typów i podnieś swoje praktyki tworzenia oprogramowania na wyższy poziom.