Tyrinėkite tipų apsaugas ir tvirtinimus TypeScript, kad padidintumėte tipų saugumą, išvengtumėte klaidų ir rašytumėte patikimesnį bei lengviau prižiūrimą kodą.
Tipų saugumo įvaldymas: išsamus tipų apsaugų ir tipų tvirtinimų vadovas
Programinės įrangos kūrimo srityje, ypač dirbant su dinamiškai tipizuojamomis kalbomis, tokiomis kaip JavaScript, išlaikyti tipų saugumą gali būti didelis iššūkis. TypeScript, JavaScript viršaibis, sprendžia šią problemą įvesdama statinį tipizavimą. Tačiau net ir su TypeScript tipų sistema atsiranda situacijų, kai kompiliatoriui reikia pagalbos nustatant teisingą kintamojo tipą. Būtent čia į pagalbą ateina tipų apsaugos (angl. type guards) ir tipų tvirtinimai (angl. type assertions). Šiame išsamiame vadove gilinsimės į šias galingas funkcijas, pateikdami praktinių pavyzdžių ir geriausių praktikų, siekiant pagerinti jūsų kodo patikimumą ir palaikomumą.
Kas yra tipų apsaugos?
Tipų apsaugos yra TypeScript išraiškos, kurios susiaurina kintamojo tipą tam tikroje apimtyje. Jos leidžia kompiliatoriui suprasti kintamojo tipą tiksliau, nei jis iš pradžių nustatė. Tai ypač naudinga dirbant su jungtiniais tipais (angl. union types) arba kai kintamojo tipas priklauso nuo vykdymo laiko sąlygų. Naudodami tipų apsaugas, galite išvengti vykdymo klaidų ir rašyti tvirtesnį kodą.
Įprastos tipų apsaugų technikos
TypeScript suteikia keletą integruotų mechanizmų tipų apsaugoms kurti:
typeof
operatorius: tikrina primityvųjį kintamojo tipą (pvz., "string", "number", "boolean", "undefined", "object", "function", "symbol", "bigint").instanceof
operatorius: tikrina, ar objektas yra tam tikros klasės egzempliorius.in
operatorius: tikrina, ar objektas turi tam tikrą savybę.- Pasirinktinės tipų apsaugos funkcijos: funkcijos, kurios grąžina tipo predikatą, t. y. specialų loginės išraiškos tipą, kurį TypeScript naudoja tipams siaurinti.
typeof
naudojimas
Operatorius typeof
yra paprastas būdas patikrinti primityvųjį kintamojo tipą. Jis grąžina eilutę, nurodančią tipą.
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // TypeScript čia žino, kad 'value' yra eilutė
} else {
console.log(value.toFixed(2)); // TypeScript čia žino, kad 'value' yra skaičius
}
}
printValue("hello"); // Išvestis: HELLO
printValue(3.14159); // Išvestis: 3.14
instanceof
naudojimas
Operatorius instanceof
tikrina, ar objektas yra tam tikros klasės egzempliorius. Tai ypač naudinga dirbant su paveldėjimu.
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 čia žino, kad 'animal' yra Dog
} else {
console.log("Generic animal sound");
}
}
const myDog = new Dog("Buddy");
const myAnimal = new Animal("Generic Animal");
makeSound(myDog); // Išvestis: Woof!
makeSound(myAnimal); // Išvestis: Generic animal sound
in
naudojimas
Operatorius in
tikrina, ar objektas turi tam tikrą savybę. Tai naudinga dirbant su objektais, kurie gali turėti skirtingas savybes priklausomai nuo jų tipo.
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
function move(animal: Bird | Fish) {
if ("fly" in animal) {
animal.fly(); // TypeScript čia žino, kad 'animal' yra Bird
} else {
animal.swim(); // TypeScript čia žino, kad 'animal' yra Fish
}
}
const myBird: Bird = { fly: () => console.log("Flying"), layEggs: () => console.log("Laying eggs") };
const myFish: Fish = { swim: () => console.log("Swimming"), layEggs: () => console.log("Laying eggs") };
move(myBird); // Išvestis: Flying
move(myFish); // Išvestis: Swimming
Pasirinktinės tipų apsaugos funkcijos
Sudėtingesniems scenarijams galite apibrėžti savo tipų apsaugos funkcijas. Šios funkcijos grąžina tipo predikatą, kuris yra loginė išraiška, kurią TypeScript naudoja kintamojo tipui susiaurinti. Tipo predikatas turi formą kintamasis is Tipas
.
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 čia žino, kad 'shape' yra Square
} else {
return Math.PI * shape.radius * shape.radius; // TypeScript čia žino, kad 'shape' yra Circle
}
}
const mySquare: Square = { kind: "square", size: 5 };
const myCircle: Circle = { kind: "circle", radius: 3 };
console.log(getArea(mySquare)); // Išvestis: 25
console.log(getArea(myCircle)); // Išvestis: 28.274333882308138
Kas yra tipų tvirtinimai?
Tipų tvirtinimai yra būdas nurodyti TypeScript kompiliatoriui, kad jūs žinote daugiau apie kintamojo tipą, nei jis šiuo metu supranta. Tai būdas apeiti TypeScript tipo nustatymą ir aiškiai nurodyti reikšmės tipą. Tačiau svarbu naudoti tipų tvirtinimus atsargiai, nes jie gali apeiti TypeScript tipų tikrinimą ir, neteisingai panaudoti, gali sukelti vykdymo klaidų.
Tipų tvirtinimai turi dvi formas:
- Laužtinių skliaustų sintaksė:
<Type>value
as
raktažodis:value as Type
as
raktažodis paprastai yra labiau pageidaujamas, nes yra suderinamesnis su JSX.
Kada naudoti tipų tvirtinimus
Tipų tvirtinimai paprastai naudojami šiais atvejais:
- Kai esate tikri dėl kintamojo tipo, kurio TypeScript negali nustatyti.
- Dirbant su kodu, kuris sąveikauja su JavaScript bibliotekomis, kurios nėra pilnai tipizuotos.
- Kai reikia konvertuoti reikšmę į konkretesnį tipą.
Tipų tvirtinimų pavyzdžiai
Aiškus tipo tvirtinimas
Šiame pavyzdyje mes tvirtiname, kad document.getElementById
iškvietimas grąžins HTMLCanvasElement
. Be tvirtinimo TypeScript nustatytų bendresnį tipą HTMLElement | null
.
const canvas = document.getElementById("myCanvas") as HTMLCanvasElement;
const ctx = canvas.getContext("2d"); // TypeScript čia žino, kad 'canvas' yra HTMLCanvasElement
if (ctx) {
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 150, 75);
}
Darbas su nežinomais tipais
Dirbant su duomenimis iš išorinio šaltinio, pavyzdžiui, API, galite gauti duomenis su nežinomu tipu. Galite naudoti tipo tvirtinimą, kad nurodytumėte TypeScript, kaip elgtis su duomenimis.
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; // Patvirtiname, kad duomenys yra tipo User
}
fetchUser(1)
.then(user => {
console.log(user.name); // TypeScript čia žino, kad 'user' yra User
})
.catch(error => {
console.error("Error fetching user:", error);
});
Atsargumo priemonės naudojant tipų tvirtinimus
Tipų tvirtinimus reikia naudoti saikingai ir atsargiai. Pernelyg dažnas tipų tvirtinimų naudojimas gali paslėpti esamas tipų klaidas ir sukelti vykdymo problemų. Štai keletas svarbių aspektų:
- Venkite priverstinių tvirtinimų: nenaudokite tipų tvirtinimų, kad priverstumėte reikšmę tapti tipu, kuriuo ji akivaizdžiai nėra. Tai gali apeiti TypeScript tipų tikrinimą ir sukelti netikėtą elgesį.
- Teikite pirmenybę tipų apsaugoms: kai įmanoma, vietoj tipų tvirtinimų naudokite tipų apsaugas. Tipų apsaugos suteikia saugesnį ir patikimesnį būdą siaurinti tipus.
- Patvirtinkite duomenis: jei tvirtinate duomenų tipą iš išorinio šaltinio, apsvarstykite galimybę patikrinti duomenis pagal schemą, kad įsitikintumėte, jog jie atitinka laukiamą tipą.
Tipų siaurinimas
Tipų apsaugos yra neatsiejamai susijusios su tipų siaurinimo (angl. type narrowing) koncepcija. Tipų siaurinimas yra procesas, kurio metu kintamojo tipas patikslinamas iki konkretesnio tipo, atsižvelgiant į vykdymo laiko sąlygas ar patikrinimus. Tipų apsaugos yra įrankiai, kuriuos naudojame tipų siaurinimui pasiekti.
TypeScript naudoja valdymo srauto analizę, kad suprastų, kaip kintamojo tipas keičiasi skirtingose kodo šakose. Kai naudojama tipo apsauga, TypeScript atnaujina savo vidinį supratimą apie kintamojo tipą, leisdama saugiai naudoti metodus ir savybes, būdingus tam tipui.
Tipų siaurinimo pavyzdys
function processValue(value: string | number | null) {
if (value === null) {
console.log("Value is null");
} else if (typeof value === "string") {
console.log(value.toUpperCase()); // TypeScript čia žino, kad 'value' yra eilutė
} else {
console.log(value.toFixed(2)); // TypeScript čia žino, kad 'value' yra skaičius
}
}
processValue("test"); // Išvestis: TEST
processValue(123.456); // Išvestis: 123.46
processValue(null); // Išvestis: Value is null
Geriausios praktikos
Norėdami efektyviai naudoti tipų apsaugas ir tipų tvirtinimus savo TypeScript projektuose, apsvarstykite šias geriausias praktikas:
- Teikite pirmenybę tipų apsaugoms, o ne tipų tvirtinimams: tipų apsaugos suteikia saugesnį ir patikimesnį būdą siaurinti tipus. Naudokite tipų tvirtinimus tik tada, kai būtina, ir atsargiai.
- Naudokite pasirinktines tipų apsaugas sudėtingiems scenarijams: dirbant su sudėtingais tipų ryšiais ar pasirinktinėmis duomenų struktūromis, apibrėžkite savo tipų apsaugos funkcijas, kad pagerintumėte kodo aiškumą ir palaikomumą.
- Dokumentuokite tipų tvirtinimus: jei naudojate tipų tvirtinimus, pridėkite komentarus, paaiškinančius, kodėl juos naudojate ir kodėl manote, kad tvirtinimas yra saugus.
- Patvirtinkite išorinius duomenis: dirbdami su duomenimis iš išorinių šaltinių, patikrinkite duomenis pagal schemą, kad įsitikintumėte, jog jie atitinka laukiamą tipą. Tam gali padėti tokios bibliotekos kaip
zod
aryup
. - Išlaikykite tikslius tipų apibrėžimus: užtikrinkite, kad jūsų tipų apibrėžimai tiksliai atspindėtų jūsų duomenų struktūrą. Netikslūs tipų apibrėžimai gali sukelti neteisingus tipų nustatymus ir vykdymo klaidas.
- Įjunkite griežtąjį režimą: naudokite TypeScript griežtąjį režimą (
strict: true
failetsconfig.json
), kad įjungtumėte griežtesnį tipų tikrinimą ir anksčiau aptiktumėte galimas klaidas.
Tarptautiniai aspektai
Kuriant programas pasaulinei auditorijai, atsižvelkite į tai, kaip tipų apsaugos ir tipų tvirtinimai gali paveikti lokalizavimo ir internacionalizavimo (i18n) pastangas. Ypač apsvarstykite:
- Duomenų formatavimas: skaičių ir datų formatai skirtingose lokalėse labai skiriasi. Atlikdami tipų patikrinimus ar tvirtinimus su skaitinėmis ar datos reikšmėmis, įsitikinkite, kad naudojate lokalės specifiką atitinkančias formatavimo ir analizės funkcijas. Pavyzdžiui, naudokite bibliotekas, tokias kaip
Intl.NumberFormat
irIntl.DateTimeFormat
, skaičiams ir datoms formatuoti bei analizuoti pagal vartotojo lokalę. Neteisingas konkretaus formato (pvz., JAV datos formato MM/DD/YYYY) numatymas gali sukelti klaidų kitose lokalėse. - Valiutų tvarkymas: valiutų simboliai ir formatavimas taip pat skiriasi visame pasaulyje. Dirbdami su piniginėmis vertėmis, naudokite bibliotekas, kurios palaiko valiutų formatavimą ir konvertavimą, ir venkite kietojo valiutų simbolių kodavimo. Užtikrinkite, kad jūsų tipų apsaugos teisingai tvarkytų skirtingus valiutų tipus ir užkirstų kelią netyčiniam valiutų maišymui.
- Simbolių kodavimas: atkreipkite dėmesį į simbolių kodavimo problemas, ypač dirbant su eilutėmis. Įsitikinkite, kad jūsų kodas teisingai tvarko Unicode simbolius ir vengia prielaidų apie simbolių rinkinius. Apsvarstykite galimybę naudoti bibliotekas, kurios teikia Unicode palaikančias eilučių manipuliavimo funkcijas.
- Iš dešinės į kairę (RTL) rašomos kalbos: jei jūsų programa palaiko RTL kalbas, tokias kaip arabų ar hebrajų, įsitikinkite, kad jūsų tipų apsaugos ir tvirtinimai teisingai tvarko teksto kryptingumą. Atkreipkite dėmesį į tai, kaip RTL tekstas gali paveikti eilučių palyginimus ir patikrinimus.
Išvada
Tipų apsaugos ir tipų tvirtinimai yra esminiai įrankiai, skirti pagerinti tipų saugumą ir rašyti tvirtesnį TypeScript kodą. Suprasdami, kaip efektyviai naudoti šias funkcijas, galite išvengti vykdymo klaidų, pagerinti kodo palaikomumą ir kurti patikimesnes programas. Prisiminkite, kad kai tik įmanoma, teikite pirmenybę tipų apsaugoms, o ne tipų tvirtinimams, dokumentuokite savo tipų tvirtinimus ir patikrinkite išorinius duomenis, kad užtikrintumėte savo tipų informacijos tikslumą. Taikydami šiuos principus galėsite kurti stabilesnę ir labiau nuspėjamą programinę įrangą, tinkamą diegti visame pasaulyje.