Lietuvių

Susipažinkite su TypeScript literaliaisiais tipais – galinga funkcija, skirta griežtiems reikšmių apribojimams, kodo aiškumui gerinti ir klaidoms išvengti. Mokykitės su praktiniais pavyzdžiais ir pažangiomis technikomis.

TypeScript literalūs tipai: tikslių reikšmių apribojimų įvaldymas

TypeScript, JavaScript viršaibis, įneša statinį tipizavimą į dinamišką interneto programavimo pasaulį. Viena galingiausių jo savybių yra literaliųjų tipų koncepcija. Literalūs tipai leidžia nurodyti tikslią reikšmę, kurią gali turėti kintamasis ar savybė, taip užtikrinant didesnį tipų saugumą ir išvengiant netikėtų klaidų. Šiame straipsnyje išsamiai nagrinėsime literaliuosius tipus, aptarsime jų sintaksę, naudojimą ir privalumus pateikdami praktinių pavyzdžių.

Kas yra literalūs tipai?

Skirtingai nuo tradicinių tipų, tokių kaip string, number ar boolean, literalūs tipai neatspindi plačios reikšmių kategorijos. Vietoj to, jie atspindi konkrečias, fiksuotas reikšmes. TypeScript palaiko trijų rūšių literaliuosius tipus:

Naudodami literaliuosius tipus, galite sukurti tikslesnius tipų apibrėžimus, kurie atspindi faktinius jūsų duomenų apribojimus, todėl kodas tampa patikimesnis ir lengviau prižiūrimas.

Eilutės literalūs tipai

Eilutės literalūs tipai yra dažniausiai naudojami literalų tipai. Jie leidžia nurodyti, kad kintamasis ar savybė gali turėti tik vieną iš iš anksto nustatytų eilutės reikšmių.

Pagrindinė sintaksė

Eilutės literalaus tipo apibrėžimo sintaksė yra paprasta:


type AllowedValues = "value1" | "value2" | "value3";

Tai apibrėžia tipą, pavadintą AllowedValues, kuris gali turėti tik eilutes „value1“, „value2“ arba „value3“.

Praktiniai pavyzdžiai

1. Spalvų paletės apibrėžimas:

Įsivaizduokite, kad kuriate vartotojo sąsajos biblioteką ir norite užtikrinti, kad vartotojai galėtų nurodyti tik iš anksto nustatytos paletės spalvas:


type Color = "red" | "green" | "blue" | "yellow";

function paintElement(element: HTMLElement, color: Color) {
  element.style.backgroundColor = color;
}

paintElement(document.getElementById("myElement")!, "red"); // Teisinga
paintElement(document.getElementById("myElement")!, "purple"); // Klaida: argumentas, kurio tipas yra '"purple"', negali būti priskirtas parametrui, kurio tipas yra 'Color'.

Šis pavyzdys parodo, kaip eilutės literalūs tipai gali priverstinai nustatyti griežtą leistinų reikšmių rinkinį, užkertant kelią programuotojams netyčia naudoti netinkamas spalvas.

2. API galinių taškų apibrėžimas:

Dirbant su API, dažnai reikia nurodyti leistinus galinius taškus. Eilutės literalūs tipai gali padėti tai užtikrinti:


type APIEndpoint = "/users" | "/posts" | "/comments";

function fetchData(endpoint: APIEndpoint) {
  // ... implementacija duomenims gauti iš nurodyto galinio taško
  console.log(`Gaunami duomenys iš ${endpoint}`);
}

fetchData("/users"); // Teisinga
fetchData("/products"); // Klaida: argumentas, kurio tipas yra '"/products"', negali būti priskirtas parametrui, kurio tipas yra 'APIEndpoint'.

Šis pavyzdys užtikrina, kad funkcija fetchData gali būti iškviesta tik su galiojančiais API galiniais taškais, sumažinant klaidų, atsirandančių dėl rašybos klaidų ar neteisingų galinių taškų pavadinimų, riziką.

3. Skirtingų kalbų tvarkymas ( internacionalizacija - i18n):

Pasaulinėse programose gali tekti tvarkyti skirtingas kalbas. Galite naudoti eilutės literaliuosius tipus, kad užtikrintumėte, jog jūsų programa palaiko tik nurodytas kalbas:


type Language = "en" | "es" | "fr" | "de" | "zh";

function translate(text: string, language: Language): string {
  // ... implementacija tekstui versti į nurodytą kalbą
  console.log(`Verčiamas tekstas '${text}' į ${language}`);
  return "Išverstas tekstas"; // Vietos rezervavimo ženklas
}

translate("Hello", "en"); // Teisinga
translate("Hello", "ja"); // Klaida: argumentas, kurio tipas yra '"ja"', negali būti priskirtas parametrui, kurio tipas yra 'Language'.

Šis pavyzdys parodo, kaip užtikrinti, kad jūsų programoje būtų naudojamos tik palaikomos kalbos.

Skaičiaus literalūs tipai

Skaičiaus literalūs tipai leidžia nurodyti, kad kintamasis ar savybė gali turėti tik konkrečią skaitinę reikšmę.

Pagrindinė sintaksė

Skaičiaus literalaus tipo apibrėžimo sintaksė yra panaši į eilutės literaliųjų tipų:


type StatusCode = 200 | 404 | 500;

Tai apibrėžia tipą, pavadintą StatusCode, kuris gali turėti tik skaičius 200, 404 arba 500.

Praktiniai pavyzdžiai

1. HTTP būsenos kodų apibrėžimas:

Galite naudoti skaičiaus literaliuosius tipus, kad atspindėtumėte HTTP būsenos kodus, užtikrinant, kad jūsų programoje būtų naudojami tik galiojantys kodai:


type HTTPStatus = 200 | 400 | 401 | 403 | 404 | 500;

function handleResponse(status: HTTPStatus) {
  switch (status) {
    case 200:
      console.log("Sėkminga!");
      break;
    case 400:
      console.log("Bloga užklausa");
      break;
    // ... kiti atvejai
    default:
      console.log("Nežinoma būsena");
  }
}

handleResponse(200); // Teisinga
handleResponse(600); // Klaida: argumentas, kurio tipas yra '600', negali būti priskirtas parametrui, kurio tipas yra 'HTTPStatus'.

Šis pavyzdys priverstinai naudoja galiojančius HTTP būsenos kodus, užkertant kelią klaidoms, atsirandančioms dėl neteisingų ar nestandartinių kodų naudojimo.

2. Fiksuotų parinkčių atvaizdavimas:

Galite naudoti skaičiaus literaliuosius tipus, kad atspindėtumėte fiksuotas parinktis konfigūracijos objekte:


type RetryAttempts = 1 | 3 | 5;

interface Config {
  retryAttempts: RetryAttempts;
}

const config1: Config = { retryAttempts: 3 }; // Teisinga
const config2: Config = { retryAttempts: 7 }; // Klaida: tipas '{ retryAttempts: 7; }' negali būti priskirtas tipui 'Config'.

Šis pavyzdys apriboja galimas retryAttempts reikšmes iki konkretaus rinkinio, pagerindamas jūsų konfigūracijos aiškumą ir patikimumą.

Loginiai literalūs tipai

Loginiai literalūs tipai atspindi konkrečias reikšmes true arba false. Nors jie gali atrodyti ne tokie universalūs kaip eilutės ar skaičiaus literalūs tipai, jie gali būti naudingi specifiniuose scenarijuose.

Pagrindinė sintaksė

Loginio literalaus tipo apibrėžimo sintaksė yra:


type IsEnabled = true | false;

Tačiau tiesioginis true | false naudojimas yra perteklinis, nes tai atitinka boolean tipą. Loginiai literalūs tipai yra naudingesni, kai derinami su kitais tipais arba sąlyginiuose tipuose.

Praktiniai pavyzdžiai

1. Sąlyginė logika su konfigūracija:

Galite naudoti loginius literaliuosius tipus, kad valdytumėte funkcijos elgseną pagal konfigūracijos vėliavėlę:


interface FeatureFlags {
  darkMode: boolean;
  newUserFlow: boolean;
}

function initializeApp(flags: FeatureFlags) {
  if (flags.darkMode) {
    // Įjungti tamsųjį režimą
    console.log("Įjungiamas tamsusis režimas...");
  } else {
    // Naudoti šviesųjį režimą
    console.log("Naudojamas šviesusis režimas...");
  }

  if (flags.newUserFlow) {
    // Įjungti naujo vartotojo srautą
    console.log("Įjungiamas naujo vartotojo srautas...");
  } else {
    // Naudoti seną vartotojo srautą
    console.log("Naudojamas senas vartotojo srautas...");
  }
}

initializeApp({ darkMode: true, newUserFlow: false });

Nors šiame pavyzdyje naudojamas standartinis boolean tipas, jį galima derinti su sąlyginiais tipais (paaiškinta vėliau), kad būtų sukurtas sudėtingesnis elgesys.

2. Diskriminuojamosios unijos (Discriminated Unions):

Loginiai literalūs tipai gali būti naudojami kaip diskriminatoriai unijos tipuose. Apsvarstykite šį pavyzdį:


interface SuccessResult {
  success: true;
  data: any;
}

interface ErrorResult {
  success: false;
  error: string;
}

type Result = SuccessResult | ErrorResult;

function processResult(result: Result) {
  if (result.success) {
    console.log("Sėkmė:", result.data);
  } else {
    console.error("Klaida:", result.error);
  }
}

processResult({ success: true, data: { name: "John" } });
processResult({ success: false, error: "Nepavyko gauti duomenų" });

Čia savybė success, kuri yra loginis literalus tipas, veikia kaip diskriminatorius, leidžiantis TypeScript susiaurinti result tipą if sakinyje.

Literaliųjų tipų derinimas su unijos tipais

Literalūs tipai yra galingiausi, kai derinami su unijos tipais (naudojant | operatorių). Tai leidžia apibrėžti tipą, kuris gali turėti vieną iš kelių konkrečių reikšmių.

Praktiniai pavyzdžiai

1. Būsenos tipo apibrėžimas:


type Status = "pending" | "in progress" | "completed" | "failed";

interface Task {
  id: number;
  description: string;
  status: Status;
}

const task1: Task = { id: 1, description: "Implement login", status: "in progress" }; // Teisinga
const task2: Task = { id: 2, description: "Implement logout", status: "done" };       // Klaida: tipas '{ id: number; description: string; status: string; }' negali būti priskirtas tipui 'Task'.

Šis pavyzdys parodo, kaip priverstinai nustatyti konkretų leistinų būsenos reikšmių rinkinį Task objektui.

2. Įrenginio tipo apibrėžimas:

Mobiliojoje programoje gali tekti tvarkyti skirtingus įrenginių tipus. Galite naudoti eilutės literaliųjų tipų uniją jiems atvaizduoti:


type DeviceType = "mobile" | "tablet" | "desktop";

function logDeviceType(device: DeviceType) {
  console.log(`Įrenginio tipas: ${device}`);
}

logDeviceType("mobile"); // Teisinga
logDeviceType("smartwatch"); // Klaida: argumentas, kurio tipas yra '"smartwatch"', negali būti priskirtas parametrui, kurio tipas yra 'DeviceType'.

Šis pavyzdys užtikrina, kad funkcija logDeviceType būtų iškviesta tik su galiojančiais įrenginių tipais.

Literalūs tipai su tipų pseudonimais (Type Aliases)

Tipų pseudonimai (naudojant raktinį žodį type) suteikia galimybę pavadinti literalųjį tipą, todėl jūsų kodas tampa skaitomesnis ir lengviau prižiūrimas.

Praktiniai pavyzdžiai

1. Valiutos kodo tipo apibrėžimas:


type CurrencyCode = "USD" | "EUR" | "GBP" | "JPY";

function formatCurrency(amount: number, currency: CurrencyCode): string {
  // ... implementacija sumai formatuoti pagal valiutos kodą
  console.log(`Formatuojama ${amount} ${currency}`);
  return "Suformatuota suma"; // Vietos rezervavimo ženklas
}

formatCurrency(100, "USD"); // Teisinga
formatCurrency(200, "CAD"); // Klaida: argumentas, kurio tipas yra '"CAD"', negali būti priskirtas parametrui, kurio tipas yra 'CurrencyCode'.

Šis pavyzdys apibrėžia CurrencyCode tipo pseudonimą valiutų kodų rinkiniui, pagerindamas funkcijos formatCurrency skaitomumą.

2. Savaitės dienos tipo apibrėžimas:


type DayOfWeek = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday";

function isWeekend(day: DayOfWeek): boolean {
  return day === "Saturday" || day === "Sunday";
}

console.log(isWeekend("Monday"));   // false
console.log(isWeekend("Saturday")); // true
console.log(isWeekend("Funday"));   // Klaida: argumentas, kurio tipas yra '"Funday"', negali būti priskirtas parametrui, kurio tipas yra 'DayOfWeek'.

Literalo išvedimas (Inference)

TypeScript dažnai gali automatiškai išvesti literaliuosius tipus pagal reikšmes, kurias priskiriate kintamiesiems. Tai ypač naudinga dirbant su const kintamaisiais.

Praktiniai pavyzdžiai

1. Eilutės literaliųjų tipų išvedimas:


const apiKey = "your-api-key"; // TypeScript nustato, kad apiKey tipas yra "your-api-key"

function validateApiKey(key: "your-api-key") {
  return key === "your-api-key";
}

console.log(validateApiKey(apiKey)); // true

const anotherKey = "invalid-key";
console.log(validateApiKey(anotherKey)); // Klaida: argumentas, kurio tipas yra 'string', negali būti priskirtas parametrui, kurio tipas yra '"your-api-key"'.

Šiame pavyzdyje TypeScript nustato apiKey tipą kaip eilutės literalųjį tipą "your-api-key". Tačiau, jei kintamajam priskirsite nekonstantinę reikšmę, TypeScript paprastai išves platesnį string tipą.

2. Skaičiaus literaliųjų tipų išvedimas:


const port = 8080; // TypeScript nustato, kad port tipas yra 8080

function startServer(portNumber: 8080) {
  console.log(`Paleidžiamas serveris ${portNumber} prievade`);
}

startServer(port); // Teisinga

const anotherPort = 3000;
startServer(anotherPort); // Klaida: argumentas, kurio tipas yra 'number', negali būti priskirtas parametrui, kurio tipas yra '8080'.

Literaliųjų tipų naudojimas su sąlyginiais tipais

Literalūs tipai tampa dar galingesni, kai derinami su sąlyginiais tipais. Sąlyginiai tipai leidžia apibrėžti tipus, kurie priklauso nuo kitų tipų, sukuriant labai lanksčias ir išraiškingas tipų sistemas.

Pagrindinė sintaksė

Sąlyginio tipo sintaksė yra:


TypeA extends TypeB ? TypeC : TypeD

Tai reiškia: jei TypeA yra priskiriamas TypeB, tada rezultato tipas yra TypeC; priešingu atveju, rezultato tipas yra TypeD.

Praktiniai pavyzdžiai

1. Būsenos susiejimas su pranešimu:


type Status = "pending" | "in progress" | "completed" | "failed";

type StatusMessage = T extends "pending"
  ? "Laukiama veiksmo"
  : T extends "in progress"
  ? "Vykdomas apdorojimas"
  : T extends "completed"
  ? "Užduotis sėkmingai baigta"
  : "Įvyko klaida";

function getStatusMessage(status: T): StatusMessage {
  switch (status) {
    case "pending":
      return "Laukiama veiksmo" as StatusMessage;
    case "in progress":
      return "Vykdomas apdorojimas" as StatusMessage;
    case "completed":
      return "Užduotis sėkmingai baigta" as StatusMessage;
    case "failed":
      return "Įvyko klaida" as StatusMessage;
    default:
      throw new Error("Netinkama būsena");
  }
}

console.log(getStatusMessage("pending"));    // Laukiama veiksmo
console.log(getStatusMessage("in progress")); // Vykdomas apdorojimas
console.log(getStatusMessage("completed"));   // Užduotis sėkmingai baigta
console.log(getStatusMessage("failed"));      // Įvyko klaida

Šis pavyzdys apibrėžia StatusMessage tipą, kuris kiekvieną galimą būseną susieja su atitinkamu pranešimu naudojant sąlyginius tipus. Funkcija getStatusMessage naudoja šį tipą, kad pateiktų tipui saugius būsenos pranešimus.

2. Tipui saugaus įvykių tvarkytuvo kūrimas:


type EventType = "click" | "mouseover" | "keydown";

type EventData = T extends "click"
  ? { x: number; y: number; } // Paspaudimo įvykio duomenys
  : T extends "mouseover"
  ? { target: HTMLElement; }   // Pelės užvedimo įvykio duomenys
  : { key: string; }             // Klavišo paspaudimo įvykio duomenys

function handleEvent(type: T, data: EventData) {
  console.log(`Tvarkomas įvykio tipas ${type} su duomenimis:`, data);
}

handleEvent("click", { x: 10, y: 20 }); // Teisinga
handleEvent("mouseover", { target: document.getElementById("myElement")! }); // Teisinga
handleEvent("keydown", { key: "Enter" }); // Teisinga

handleEvent("click", { key: "Enter" }); // Klaida: argumentas, kurio tipas yra '{ key: string; }', negali būti priskirtas parametrui, kurio tipas yra '{ x: number; y: number; }'.

Šis pavyzdys sukuria EventData tipą, kuris apibrėžia skirtingas duomenų struktūras priklausomai nuo įvykio tipo. Tai leidžia užtikrinti, kad kiekvienam įvykio tipui į funkciją handleEvent būtų perduoti teisingi duomenys.

Geriausios praktikos naudojant literaliuosius tipus

Norėdami efektyviai naudoti literaliuosius tipus savo TypeScript projektuose, apsvarstykite šias geriausias praktikas:

Literaliųjų tipų naudojimo privalumai

Išvada

TypeScript literalūs tipai yra galinga funkcija, leidžianti priverstinai nustatyti griežtus reikšmių apribojimus, pagerinti kodo aiškumą ir išvengti klaidų. Suprasdami jų sintaksę, naudojimą ir privalumus, galite pasinaudoti literaliaisiais tipais, kad sukurtumėte patikimesnes ir lengviau prižiūrimas TypeScript programas. Nuo spalvų palečių ir API galinių taškų apibrėžimo iki skirtingų kalbų tvarkymo ir tipui saugių įvykių tvarkytuvų kūrimo – literalūs tipai siūlo platų praktinių pritaikymų spektrą, galintį žymiai pagerinti jūsų kūrimo procesą.