Raziščite varovala in trditve o tipih v TypeScriptu za večjo tipsko varnost, preprečevanje napak in pisanje robustnejše kode s praktičnimi primeri.
Obvladovanje tipske varnosti: celovit vodnik po varovalih tipov in trditvah o tipih
V svetu razvoja programske opreme, še posebej pri delu z dinamično tipiziranimi jeziki, kot je JavaScript, je ohranjanje tipske varnosti lahko velik izziv. TypeScript, nadmnožica JavaScripta, ta problem rešuje z uvedbo statičnega tipiziranja. Vendar pa se tudi pri uporabi tipskega sistema v TypeScriptu pojavijo situacije, kjer prevajalnik potrebuje pomoč pri sklepanju o pravilnem tipu spremenljivke. Tu nastopijo varovala tipov (type guards) in trditve o tipih (type assertions). Ta celovit vodnik se bo poglobil v te zmogljive funkcije, ponudil praktične primere in najboljše prakse za izboljšanje zanesljivosti in vzdržljivosti vaše kode.
Kaj so varovala tipov?
Varovala tipov so izrazi v TypeScriptu, ki zožijo tip spremenljivke znotraj določenega obsega. Prevajalniku omogočajo, da natančneje razume tip spremenljivke, kot ga je prvotno sklepal. To je še posebej uporabno pri delu z unijskimi tipi ali kadar je tip spremenljivke odvisen od pogojev med izvajanjem. Z uporabo varoval tipov se lahko izognete napakam med izvajanjem in pišete bolj robustno kodo.
Pogoste tehnike varoval tipov
TypeScript ponuja več vgrajenih mehanizmov za ustvarjanje varoval tipov:
- Operator
typeof
: Preveri primitivni tip spremenljivke (npr. "string", "number", "boolean", "undefined", "object", "function", "symbol", "bigint"). - Operator
instanceof
: Preveri, ali je objekt instanca določenega razreda. - Operator
in
: Preveri, ali ima objekt določeno lastnost. - Funkcije varoval tipov po meri: Funkcije, ki vrnejo tipski predikat, kar je posebna vrsta logičnega izraza, ki ga TypeScript uporablja za ožanje tipov.
Uporaba typeof
Operator typeof
je preprost način za preverjanje primitivnega tipa spremenljivke. Vrne niz, ki označuje tip.
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // TypeScript tukaj ve, da je 'value' niz
} else {
console.log(value.toFixed(2)); // TypeScript tukaj ve, da je 'value' število
}
}
printValue("hello"); // Izhod: HELLO
printValue(3.14159); // Izhod: 3.14
Uporaba instanceof
Operator instanceof
preveri, ali je objekt instanca določenega razreda. To je še posebej uporabno pri delu z dedovanjem.
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
bark() {
console.log("Woof!");
}
}
function makeSound(animal: Animal) {
if (animal instanceof Dog) {
animal.bark(); // TypeScript tukaj ve, da je 'animal' tipa Dog
} else {
console.log("Splošen živalski zvok");
}
}
const myDog = new Dog("Buddy");
const myAnimal = new Animal("Splošna žival");
makeSound(myDog); // Izhod: Woof!
makeSound(myAnimal); // Izhod: Splošen živalski zvok
Uporaba in
Operator in
preveri, ali ima objekt določeno lastnost. To je uporabno pri delu z objekti, ki imajo lahko različne lastnosti glede na njihov tip.
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
function move(animal: Bird | Fish) {
if ("fly" in animal) {
animal.fly(); // TypeScript tukaj ve, da je 'animal' tipa Bird
} else {
animal.swim(); // TypeScript tukaj ve, da je 'animal' tipa Fish
}
}
const myBird: Bird = { fly: () => console.log("Letenje"), layEggs: () => console.log("Leženje jajc") };
const myFish: Fish = { swim: () => console.log("Plavanje"), layEggs: () => console.log("Leženje jajc") };
move(myBird); // Izhod: Letenje
move(myFish); // Izhod: Plavanje
Funkcije varoval tipov po meri
Za bolj zapletene scenarije lahko definirate lastne funkcije varoval tipov. Te funkcije vrnejo tipski predikat, ki je logični izraz, ki ga TypeScript uporablja za ožanje tipa spremenljivke. Tipski predikat ima obliko spremenljivka is Tip
.
interface Square {
kind: "square";
size: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Circle;
function isSquare(shape: Shape): shape is Square {
return shape.kind === "square";
}
function getArea(shape: Shape) {
if (isSquare(shape)) {
return shape.size * shape.size; // TypeScript tukaj ve, da je 'shape' tipa Square
} else {
return Math.PI * shape.radius * shape.radius; // TypeScript tukaj ve, da je 'shape' tipa Circle
}
}
const mySquare: Square = { kind: "square", size: 5 };
const myCircle: Circle = { kind: "circle", radius: 3 };
console.log(getArea(mySquare)); // Izhod: 25
console.log(getArea(myCircle)); // Izhod: 28.274333882308138
Kaj so trditve o tipih?
Trditve o tipih so način, kako prevajalniku TypeScript poveste, da o tipu spremenljivke veste več, kot on trenutno razume. So način za preglasitev sklepanja o tipih v TypeScriptu in eksplicitno določanje tipa vrednosti. Vendar je pomembno, da trditve o tipih uporabljate previdno, saj lahko zaobidejo preverjanje tipov v TypeScriptu in potencialno vodijo do napak med izvajanjem, če se uporabljajo nepravilno.
Trditve o tipih imajo dve obliki:
- Sintaksa z ostrimi oklepaji:
<Tip>vrednost
- Ključna beseda
as
:vrednost as Tip
Ključna beseda as
je na splošno prednostna, ker je bolj združljiva z JSX.
Kdaj uporabiti trditve o tipih
Trditve o tipih se običajno uporabljajo v naslednjih scenarijih:
- Ko ste prepričani o tipu spremenljivke, ki ga TypeScript ne more sklepati.
- Pri delu s kodo, ki interagira z JavaScript knjižnicami, ki niso v celoti tipizirane.
- Ko morate vrednost pretvoriti v bolj specifičen tip.
Primeri trditev o tipih
Eksplicitna trditev o tipu
V tem primeru trdimo, da bo klic document.getElementById
vrnil HTMLCanvasElement
. Brez trditve bi TypeScript sklepal o bolj splošnem tipu HTMLElement | null
.
const canvas = document.getElementById("myCanvas") as HTMLCanvasElement;
const ctx = canvas.getContext("2d"); // TypeScript tukaj ve, da je 'canvas' HTMLCanvasElement
if (ctx) {
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 150, 75);
}
Delo z neznanimi tipi
Pri delu s podatki iz zunanjega vira, kot je API, lahko prejmete podatke z neznanim tipom. Z uporabo trditve o tipu lahko TypeScriptu poveste, kako naj obravnava podatke.
interface User {
id: number;
name: string;
email: string;
}
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
const data = await response.json();
return data as User; // Trdimo, da so podatki tipa User
}
fetchUser(1)
.then(user => {
console.log(user.name); // TypeScript tukaj ve, da je 'user' tipa User
})
.catch(error => {
console.error("Napaka pri pridobivanju uporabnika:", error);
});
Previdnost pri uporabi trditev o tipih
Trditve o tipih je treba uporabljati zmerno in previdno. Prekomerna uporaba trditev o tipih lahko prikrije osnovne napake v tipih in vodi do težav med izvajanjem. Tu je nekaj ključnih premislekov:
- Izogibajte se vsiljenim trditvam: Ne uporabljajte trditev o tipih, da bi vrednost vsilili v tip, ki očitno ni. To lahko zaobide preverjanje tipov v TypeScriptu in vodi do nepričakovanega obnašanja.
- Raje uporabite varovala tipov: Kadar je mogoče, namesto trditev o tipih uporabite varovala tipov. Varovala tipov zagotavljajo varnejši in bolj zanesljiv način za ožanje tipov.
- Preverite podatke: Če trdite o tipu podatkov iz zunanjega vira, razmislite o preverjanju podatkov glede na shemo, da zagotovite, da se ujemajo s pričakovanim tipom.
Ožanje tipov
Varovala tipov so neločljivo povezana s konceptom ožanja tipov (type narrowing). Ožanje tipov je proces izboljšanja tipa spremenljivke v bolj specifičen tip na podlagi pogojev ali preverjanj med izvajanjem. Varovala tipov so orodja, ki jih uporabljamo za doseganje ožanja tipov.
TypeScript uporablja analizo kontrolnega toka, da razume, kako se tip spremenljivke spreminja v različnih vejah kode. Ko se uporabi varovalo tipa, TypeScript posodobi svoje notranje razumevanje tipa spremenljivke, kar vam omogoča varno uporabo metod in lastnosti, specifičnih za ta tip.
Primer ožanja tipov
function processValue(value: string | number | null) {
if (value === null) {
console.log("Vrednost je null");
} else if (typeof value === "string") {
console.log(value.toUpperCase()); // TypeScript tukaj ve, da je 'value' niz
} else {
console.log(value.toFixed(2)); // TypeScript tukaj ve, da je 'value' število
}
}
processValue("test"); // Izhod: TEST
processValue(123.456); // Izhod: 123.46
processValue(null); // Izhod: Vrednost je null
Najboljše prakse
Za učinkovito uporabo varoval tipov in trditev o tipih v vaših projektih TypeScript upoštevajte naslednje najboljše prakse:
- Dajte prednost varovalom tipov pred trditvami o tipih: Varovala tipov zagotavljajo varnejši in bolj zanesljiv način za ožanje tipov. Trditve o tipih uporabljajte le, kadar je to nujno in s previdnostjo.
- Uporabite varovala tipov po meri za zapletene scenarije: Pri delu z zapletenimi razmerji med tipi ali podatkovnimi strukturami po meri definirajte lastne funkcije varoval tipov za izboljšanje jasnosti in vzdržljivosti kode.
- Dokumentirajte trditve o tipih: Če uporabljate trditve o tipih, dodajte komentarje, da pojasnite, zakaj jih uporabljate in zakaj menite, da je trditev varna.
- Preverite zunanje podatke: Pri delu s podatki iz zunanjih virov preverite podatke glede na shemo, da zagotovite, da se ujemajo s pričakovanim tipom. Knjižnice, kot sta
zod
aliyup
, so lahko pri tem v pomoč. - Ohranjajte natančne definicije tipov: Zagotovite, da vaše definicije tipov natančno odražajo strukturo vaših podatkov. Nenatančne definicije tipov lahko vodijo do napačnega sklepanja o tipih in napak med izvajanjem.
- Omogočite strogi način (Strict Mode): Uporabite strogi način v TypeScriptu (
strict: true
vtsconfig.json
), da omogočite strožje preverjanje tipov in zgodaj odkrijete potencialne napake.
Mednarodni vidiki
Pri razvoju aplikacij za globalno občinstvo je treba paziti, kako lahko varovala tipov in trditve o tipih vplivajo na lokalizacijo in internacionalizacijo (i18n). Še posebej upoštevajte:
- Oblikovanje podatkov: Formati številk in datumov se med različnimi lokalnostmi močno razlikujejo. Pri izvajanju preverjanj tipov ali trditev o številskih ali datumskih vrednostih zagotovite, da uporabljate funkcije za oblikovanje in razčlenjevanje, ki upoštevajo lokalnost. Na primer, uporabite knjižnice, kot sta
Intl.NumberFormat
inIntl.DateTimeFormat
za oblikovanje in razčlenjevanje številk in datumov v skladu z lokalnostjo uporabnika. Napačno predpostavljanje določenega formata (npr. ameriški format datuma MM/DD/YYYY) lahko privede do napak v drugih lokalnostih. - Obravnava valut: Simboli in oblikovanje valut se prav tako razlikujejo po svetu. Pri delu z denarnimi vrednostmi uporabljajte knjižnice, ki podpirajo oblikovanje in pretvorbo valut, ter se izogibajte trdo kodiranim simbolom valut. Zagotovite, da vaša varovala tipov pravilno obravnavajo različne tipe valut in preprečujejo nenamerno mešanje valut.
- Kodiranje znakov: Zavedajte se težav s kodiranjem znakov, še posebej pri delu z nizi. Zagotovite, da vaša koda pravilno obravnava znake Unicode in se izogiba predpostavkam o naborih znakov. Razmislite o uporabi knjižnic, ki ponujajo funkcije za manipulacijo nizov, ki podpirajo Unicode.
- Jeziki, ki se pišejo od desne proti levi (RTL): Če vaša aplikacija podpira jezike RTL, kot sta arabščina ali hebrejščina, zagotovite, da vaša varovala tipov in trditve pravilno obravnavajo smer besedila. Bodite pozorni na to, kako lahko besedilo RTL vpliva na primerjave in preverjanje nizov.
Zaključek
Varovala tipov in trditve o tipih so ključna orodja za izboljšanje tipske varnosti in pisanje bolj robustne kode v TypeScriptu. Z razumevanjem, kako učinkovito uporabljati te funkcije, lahko preprečite napake med izvajanjem, izboljšate vzdržljivost kode in ustvarite bolj zanesljive aplikacije. Ne pozabite, da je treba dati prednost varovalom tipov pred trditvami o tipih, kjer je to mogoče, dokumentirati trditve o tipih in preverjati zunanje podatke, da zagotovite točnost informacij o tipih. Uporaba teh načel vam bo omogočila ustvarjanje stabilnejše in bolj predvidljive programske opreme, primerne za globalno uporabo.