Lietuvių

Išmokite, kaip panaudoti „TypeScript“ susietuosius tipus dinamiškai transformuoti objektų formas, sukuriant tvirtą ir lengvai prižiūrimą kodą globalioms programoms.

TypeScript susietieji tipai (Mapped Types) dinamiškoms objektų transformacijoms: išsamus vadovas

„TypeScript“, pabrėžiantis statinį tipizavimą, suteikia programuotojams galimybę rašyti patikimesnį ir lengviau prižiūrimą kodą. Ypač svarbi funkcija, kuri prie to ženkliai prisideda, yra susietieji tipai (angl. mapped types). Šiame vadove gilinamasi į „TypeScript“ susietųjų tipų pasaulį, pateikiant išsamų jų funkcionalumo, privalumų ir praktinio pritaikymo supratimą, ypač kuriant globalius programinės įrangos sprendimus.

Pagrindinių koncepcijų supratimas

Iš esmės, susietasis tipas leidžia sukurti naują tipą, remiantis esamo tipo savybėmis. Jūs apibrėžiate naują tipą iteruodami per kito tipo raktus ir taikydami transformacijas reikšmėms. Tai nepaprastai naudinga scenarijuose, kai reikia dinamiškai keisti objektų struktūrą, pavyzdžiui, keisti savybių duomenų tipus, padaryti savybes neprivalomas arba pridėti naujų savybių, pagrįstų esamomis.

Pradėkime nuo pagrindų. Apsvarstykime paprastą sąsają:

interface Person {
  name: string;
  age: number;
  email: string;
}

Dabar apibrėžkime susietąjį tipą, kuris visas Person savybes padaro neprivalomas:

type OptionalPerson = { 
  [K in keyof Person]?: Person[K];
};

Šiame pavyzdyje:

Gautas OptionalPerson tipas iš esmės atrodo taip:

{
  name?: string;
  age?: number;
  email?: string;
}

Tai parodo susietųjų tipų galią dinamiškai modifikuoti esamus tipus.

Susietųjų tipų sintaksė ir struktūra

Susietojo tipo sintaksė yra gana specifinė ir laikosi šios bendros struktūros:

type NewType = { 
  [Key in KeysType]: ValueType;
};

Išnagrinėkime kiekvieną komponentą:

Pavyzdys: Savybių tipų transformavimas

Įsivaizduokite, kad reikia konvertuoti visas skaitines objekto savybes į eilutes. Štai kaip tai galėtumėte padaryti naudodami susietąjį tipą:

interface Product {
  id: number;
  name: string;
  price: number;
  quantity: number;
}

type StringifiedProduct = {
  [K in keyof Product]: Product[K] extends number ? string : Product[K];
};

Šiuo atveju mes:

Gautas StringifiedProduct tipas būtų:

{
  id: string;
  name: string;
  price: string;
  quantity: string;
}

Pagrindinės funkcijos ir metodai

1. keyof ir indeksų signatūrų naudojimas

Kaip parodyta anksčiau, keyof yra pagrindinis įrankis dirbant su susietaisiais tipais. Jis leidžia iteruoti per tipo raktus. Indeksų signatūros suteikia būdą apibrėžti savybių tipą, kai iš anksto nežinote raktų, bet vis tiek norite juos transformuoti.

Pavyzdys: Visų savybių transformavimas pagal indekso signatūrą

interface StringMap {
  [key: string]: number;
}

type StringMapToString = {
  [K in keyof StringMap]: string;
};

Čia visos skaitinės reikšmės „StringMap“ yra konvertuojamos į eilutes naujame tipe.

2. Sąlyginiai tipai susietuosiuose tipuose

Sąlyginiai tipai yra galinga „TypeScript“ funkcija, leidžianti išreikšti tipų ryšius, pagrįstus sąlygomis. Derinant su susietaisiais tipais, jie leidžia atlikti labai sudėtingas transformacijas.

Pavyzdys: `null` ir `undefined` pašalinimas iš tipo

type NonNullableProperties = {
  [K in keyof T]: T[K] extends (null | undefined) ? never : T[K];
};

Šis susietasis tipas iteruoja per visus tipo T raktus ir naudoja sąlyginį tipą, kad patikrintų, ar reikšmė leidžia `null` arba `undefined`. Jei taip, tipas tampa `never`, efektyviai pašalinant tą savybę; kitu atveju, jis išlaiko pradinį tipą. Šis metodas daro tipus tvirtesnius, pašalindamas potencialiai problemiškas `null` ar `undefined` reikšmes, gerindamas kodo kokybę ir atitikdamas geriausias globalios programinės įrangos kūrimo praktikas.

3. Pagalbiniai tipai efektyvumui

„TypeScript“ teikia integruotus pagalbinius tipus, kurie supaprastina įprastas tipų manipuliavimo užduotis. Šie tipai užkulisiuose naudoja susietuosius tipus.

Pavyzdys: Pick ir Omit naudojimas

interface User {
  id: number;
  name: string;
  email: string;
  role: string;
}

type UserSummary = Pick;
// { id: number; name: string; }

type UserWithoutEmail = Omit;
// { id: number; name: string; role: string; }

Šie pagalbiniai tipai sutaupo jums nuo pasikartojančių susietųjų tipų apibrėžimų rašymo ir pagerina kodo skaitomumą. Jie ypač naudingi globaliame programavime, valdant skirtingus duomenų vaizdus ar prieigos lygius, atsižvelgiant į vartotojo teises ar programos kontekstą.

Pritaikymas ir pavyzdžiai realiame pasaulyje

1. Duomenų patvirtinimas ir transformavimas

Susietieji tipai yra neįkainojami patvirtinant ir transformuojant duomenis, gautus iš išorinių šaltinių (API, duomenų bazių, vartotojo įvesties). Tai labai svarbu globaliose programose, kur gali tekti dirbti su duomenimis iš daugybės skirtingų šaltinių ir reikia užtikrinti duomenų vientisumą. Jie leidžia apibrėžti konkrečias taisykles, tokias kaip duomenų tipo patvirtinimas, ir automatiškai modifikuoti duomenų struktūras pagal šias taisykles.

Pavyzdys: API atsakymo konvertavimas

interface ApiResponse {
  userId: string;
  id: string;
  title: string;
  completed: boolean;
}

type CleanedApiResponse = {
  [K in keyof ApiResponse]:
    K extends 'userId' | 'id' ? number :
    K extends 'title' ? string :
    K extends 'completed' ? boolean : any;
};

Šis pavyzdys transformuoja userId ir id savybes (kurios iš API gaunamos kaip eilutės) į skaičius. title savybė teisingai tipizuojama kaip eilutė, o completed lieka loginio tipo (boolean). Tai užtikrina duomenų nuoseklumą ir padeda išvengti galimų klaidų tolimesniame apdorojime.

2. Daugkartinio naudojimo komponentų savybių (props) kūrimas

„React“ ir kitose vartotojo sąsajos sistemose (UI frameworks), susietieji tipai gali supaprastinti daugkartinio naudojimo komponentų savybių kūrimą. Tai ypač svarbu kuriant globalius vartotojo sąsajos komponentus, kurie turi prisitaikyti prie skirtingų lokalizacijų ir vartotojo sąsajų.

Pavyzdys: Lokalizacijos tvarkymas

interface TextProps {
  textId: string;
  defaultText: string;
  locale: string;
}

type LocalizedTextProps = {
  [K in keyof TextProps as `localized-${K}`]: TextProps[K];
};

Šiame kode naujas tipas LocalizedTextProps prideda priešdėlį prie kiekvieno TextProps savybės pavadinimo. Pavyzdžiui, textId tampa localized-textId, kas naudinga nustatant komponento savybes. Šį modelį galima naudoti generuojant savybes, kurios leidžia dinamiškai keisti tekstą atsižvelgiant į vartotojo lokalizaciją. Tai būtina kuriant daugiakalbes vartotojo sąsajas, kurios sklandžiai veikia skirtinguose regionuose ir kalbose, pavyzdžiui, elektroninės komercijos programose ar tarptautinėse socialinių tinklų platformose. Transformuotos savybės suteikia programuotojui daugiau kontrolės ties lokalizacija ir galimybę sukurti nuoseklią vartotojo patirtį visame pasaulyje.

3. Dinaminis formų generavimas

Susietieji tipai yra naudingi dinamiškai generuojant formos laukus pagal duomenų modelius. Globaliose programose tai gali būti naudinga kuriant formas, kurios prisitaiko prie skirtingų vartotojų rolių ar duomenų reikalavimų.

Pavyzdys: Automatinis formos laukų generavimas pagal objekto raktus

interface UserProfile {
  firstName: string;
  lastName: string;
  email: string;
  phoneNumber: string;
}

type FormFields = {
  [K in keyof UserProfile]: {
    label: string;
    type: string;
    required: boolean;
  };
};

Tai leidžia apibrėžti formos struktūrą remiantis UserProfile sąsajos savybėmis. Tai padeda išvengti poreikio rankiniu būdu apibrėžti formos laukus, pagerinant jūsų programos lankstumą ir priežiūrą.

Pažangios susietųjų tipų technikos

1. Raktų pervadinimas (Key Remapping)

„TypeScript 4.1“ pristatė raktų pervadinimą susietuosiuose tipuose. Tai leidžia pervadinti raktus transformuojant tipą. Tai ypač naudinga pritaikant tipus skirtingiems API reikalavimams arba kai norite sukurti vartotojui draugiškesnius savybių pavadinimus.

Pavyzdys: Savybių pervadinimas

interface Product {
  productId: number;
  productName: string;
  productDescription: string;
  price: number;
}

type ProductDto = {
  [K in keyof Product as `dto_${K}`]: Product[K];
};

Tai pervadina kiekvieną Product tipo savybę, pridedant priešdėlį dto_. Tai vertinga, kai reikia susieti duomenų modelius ir API, kurie naudoja skirtingą pavadinimų suteikimo konvenciją. Tai svarbu tarptautinėje programinės įrangos kūrimo srityje, kur programos sąveikauja su keliomis vidinėmis sistemomis (back-end), kurios gali turėti specifines pavadinimų konvencijas, leidžiančias sklandžią integraciją.

2. Sąlyginis raktų pervadinimas

Galite derinti raktų pervadinimą su sąlyginiais tipais sudėtingesnėms transformacijoms, leidžiančioms pervadinti arba pašalinti savybes pagal tam tikrus kriterijus. Ši technika leidžia atlikti sudėtingas transformacijas.

Pavyzdys: Savybių pašalinimas iš DTO


interface Product {
    id: number;
    name: string;
    description: string;
    price: number;
    category: string;
    isActive: boolean;
}

type ProductDto = {
    [K in keyof Product as K extends 'description' | 'isActive' ? never : K]: Product[K]
}

Čia description ir isActive savybės yra efektyviai pašalinamos iš sugeneruoto ProductDto tipo, nes raktas išsisprendžia į never, jei savybė yra „description“ arba „isActive“. Tai leidžia kurti specifinius duomenų perdavimo objektus (DTO), kuriuose yra tik būtini duomenys skirtingoms operacijoms. Toks selektyvus duomenų perdavimas yra gyvybiškai svarbus optimizavimui ir privatumui globalioje programoje. Duomenų perdavimo apribojimai užtikrina, kad tinklais siunčiami tik atitinkami duomenys, mažinant pralaidumo naudojimą ir gerinant vartotojo patirtį. Tai atitinka globalias privatumo taisykles.

3. Susietųjų tipų naudojimas su generiniais tipais (Generics)

Susietuosius tipus galima derinti su generiniais tipais, siekiant sukurti labai lanksčius ir daugkartinio naudojimo tipų apibrėžimus. Tai leidžia rašyti kodą, kuris gali apdoroti įvairius tipus, žymiai padidinant kodo pakartotinį naudojimą ir priežiūrą, kas ypač vertinga dideliuose projektuose ir tarptautinėse komandose.

Pavyzdys: Generinė funkcija objektų savybėms transformuoti


function transformObjectValues(obj: T, transform: (value: T[K]) => U): {
    [P in keyof T]: U;
} {
    const result: any = {};
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[key] = transform(obj[key]);
        }
    }
    return result;
}

interface Order {
    id: number;
    items: string[];
    total: number;
}

const order: Order = {
    id: 123,
    items: ['apple', 'banana'],
    total: 5.99,
};

const stringifiedOrder = transformObjectValues(order, (value) => String(value));
// stringifiedOrder: { id: string; items: string; total: string; }

Šiame pavyzdyje funkcija transformObjectValues naudoja generinius tipus (T, K, ir U), kad priimtų objektą (obj) tipo T ir transformavimo funkciją, kuri priima vieną savybę iš T ir grąžina reikšmę tipo U. Tuomet funkcija grąžina naują objektą, turintį tuos pačius raktus kaip ir originalus objektas, bet su reikšmėmis, kurios buvo transformuotos į tipą U.

Geriausios praktikos ir svarstymai

1. Tipų saugumas ir kodo priežiūra

Vienas didžiausių „TypeScript“ ir susietųjų tipų privalumų yra padidintas tipų saugumas. Apibrėždami aiškius tipus, klaidas aptinkate anksčiau kūrimo procese, mažindami vykdymo metu pasitaikančių klaidų tikimybę. Jie daro jūsų kodą lengviau suprantamą ir refaktorizuojamą, ypač dideliuose projektuose. Be to, susietųjų tipų naudojimas užtikrina, kad kodas yra mažiau linkęs į klaidas, kai programinė įranga plečiasi, prisitaikydama prie milijonų vartotojų poreikių visame pasaulyje.

2. Skaitomumas ir kodo stilius

Nors susietieji tipai gali būti galingi, svarbu juos rašyti aiškiai ir skaitomai. Naudokite prasmingus kintamųjų pavadinimus ir komentuokite kodą, kad paaiškintumėte sudėtingų transformacijų tikslą. Kodo aiškumas užtikrina, kad įvairių sričių programuotojai gali skaityti ir suprasti kodą. Nuoseklumas stiliuje, pavadinimų suteikimo konvencijose ir formatavime daro kodą prieinamesnį ir prisideda prie sklandesnio kūrimo proceso, ypač tarptautinėse komandose, kur skirtingi nariai dirba su skirtingomis programinės įrangos dalimis.

3. Perteklinis naudojimas ir sudėtingumas

Venkite perteklinio susietųjų tipų naudojimo. Nors jie yra galingi, jie gali padaryti kodą mažiau skaitomą, jei naudojami per daug arba kai yra paprastesnių sprendimų. Apsvarstykite, ar tiesmukas sąsajos apibrėžimas ar paprasta pagalbinė funkcija galėtų būti tinkamesnis sprendimas. Jei jūsų tipai tampa pernelyg sudėtingi, juos gali būti sunku suprasti ir prižiūrėti. Visada atsižvelkite į pusiausvyrą tarp tipų saugumo ir kodo skaitomumo. Šios pusiausvyros išlaikymas užtikrina, kad visi tarptautinės komandos nariai galėtų efektyviai skaityti, suprasti ir prižiūrėti kodo bazę.

4. Našumas

Susietieji tipai daugiausia veikia kompiliavimo metu atliekamą tipų patikrinimą ir paprastai nekelia didelio našumo praradimo vykdymo metu. Tačiau pernelyg sudėtingos tipų manipuliacijos potencialiai gali sulėtinti kompiliavimo procesą. Sumažinkite sudėtingumą ir atsižvelkite į poveikį kūrimo laikui, ypač dideliuose projektuose arba komandose, išsidėsčiusiose skirtingose laiko juostose ir turinčiose skirtingus išteklių apribojimus.

Išvada

„TypeScript“ susietieji tipai siūlo galingą įrankių rinkinį dinamiškam objektų formų transformavimui. Jie yra neįkainojami kuriant tipų saugų, prižiūrimą ir daugkartinio naudojimo kodą, ypač dirbant su sudėtingais duomenų modeliais, API sąveikomis ir vartotojo sąsajos komponentų kūrimu. Įvaldę susietuosius tipus, galite rašyti tvirtesnes ir labiau pritaikomas programas, kurdami geresnę programinę įrangą pasaulinei rinkai. Tarptautinėms komandoms ir pasauliniams projektams susietųjų tipų naudojimas užtikrina tvirtą kodo kokybę ir priežiūrą. Čia aptartos funkcijos yra labai svarbios kuriant pritaikomą ir mastelį keičiančią programinę įrangą, gerinant kodo priežiūrą ir kuriant geresnę patirtį vartotojams visame pasaulyje. Susietieji tipai palengvina kodo atnaujinimą, kai pridedamos ar modifikuojamos naujos funkcijos, API ar duomenų modeliai.