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:
- Eilutės literalūs tipai: Atspindi konkrečias eilutės reikšmes.
- Skaičiaus literalūs tipai: Atspindi konkrečias skaitines reikšmes.
- Loginiai literalūs tipai: Atspindi konkrečias reikšmes
true
arbafalse
.
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:
- Naudokite literaliuosius tipus apribojimams įgyvendinti: Nustatykite vietas savo kode, kur kintamieji ar savybės turėtų turėti tik konkrečias reikšmes, ir naudokite literaliuosius tipus šiems apribojimams įgyvendinti.
- Derinkite literaliuosius tipus su unijos tipais: Kurkite lankstesnius ir išraiškingesnius tipų apibrėžimus derindami literaliuosius tipus su unijos tipais.
- Naudokite tipų pseudonimus skaitomumui gerinti: Suteikite prasmingus pavadinimus savo literaliųjų tipų pseudonimams, kad pagerintumėte kodo skaitomumą ir priežiūrą.
- Pasinaudokite literalo išvedimu: Naudokite
const
kintamuosius, kad pasinaudotumėte TypeScript literalo išvedimo galimybėmis. - Apsvarstykite galimybę naudoti enums: Fiksuotam reikšmių rinkiniui, kuris yra logiškai susijęs ir reikalauja pagrindinio skaitinio atvaizdavimo, naudokite enums vietoj literaliųjų tipų. Tačiau atsižvelkite į enums trūkumus, palyginti su literaliaisiais tipais, tokius kaip vykdymo laiko sąnaudos ir galimybė mažiau griežtai tikrinti tipus tam tikrais scenarijais.
- Naudokite sąlyginius tipus sudėtingiems scenarijams: Kai reikia apibrėžti tipus, kurie priklauso nuo kitų tipų, naudokite sąlyginius tipus kartu su literaliaisiais tipais, kad sukurtumėte labai lanksčias ir galingas tipų sistemas.
- Balansuokite tarp griežtumo ir lankstumo: Nors literalūs tipai suteikia puikų tipų saugumą, būkite atsargūs, kad per daug neapribotumėte savo kodo. Svarstydami, ar naudoti literaliuosius tipus, įvertinkite kompromisus tarp griežtumo ir lankstumo.
Literaliųjų tipų naudojimo privalumai
- Padidintas tipų saugumas: Literalūs tipai leidžia apibrėžti tikslesnius tipų apribojimus, sumažinant vykdymo laiko klaidų, atsirandančių dėl netinkamų reikšmių, riziką.
- Geresnis kodo aiškumas: Aiškiai nurodant leistinas reikšmes kintamiesiems ir savybėms, literalūs tipai padaro jūsų kodą skaitomesnį ir lengviau suprantamą.
- Geresnis automatinis užbaigimas (Autocompletion): IDE gali pateikti geresnius automatinio užbaigimo pasiūlymus, pagrįstus literaliaisiais tipais, pagerindama programuotojo patirtį.
- Refaktorinimo saugumas: Literalūs tipai gali padėti jums su pasitikėjimu refaktorinti kodą, nes TypeScript kompiliatorius pagaus bet kokias tipų klaidas, atsiradusias refaktorinimo proceso metu.
- Sumažinta kognityvinė apkrova: Sumažindami galimų reikšmių apimtį, literalūs tipai gali sumažinti kognityvinę programuotojų apkrovą.
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ą.