Slovenščina

Celovit vodnik po zmogljivih preslikanih in pogojnih tipih v TypeScriptu, vključno s praktičnimi primeri in naprednimi primeri uporabe za ustvarjanje robustnih in tipsko varnih aplikacij.

Obvladovanje preslikanih in pogojnih tipov v TypeScriptu

TypeScript, nadmnožica JavaScripta, ponuja zmogljive funkcije za ustvarjanje robustnih in vzdržljivih aplikacij. Med temi funkcijami izstopata Preslikani tipi (Mapped Types) in Pogojni tipi (Conditional Types) kot ključni orodji za napredno manipulacijo s tipi. Ta vodnik ponuja celovit pregled teh konceptov, raziskuje njihovo sintakso, praktično uporabo in napredne primere uporabe. Ne glede na to, ali ste izkušen razvijalec TypeScripta ali šele začenjate svojo pot, vas bo ta članek opremil z znanjem za učinkovito uporabo teh funkcij.

Kaj so preslikani tipi?

Preslikani tipi vam omogočajo ustvarjanje novih tipov s transformacijo obstoječih. Iterirajo čez lastnosti obstoječega tipa in na vsako lastnost uporabijo transformacijo. To je še posebej uporabno za ustvarjanje različic obstoječih tipov, na primer za označevanje vseh lastnosti kot neobveznih ali samo za branje.

Osnovna sintaksa

Sintaksa za preslikani tip je naslednja:

type NewType<T> = {
  [K in keyof T]: Transformation;
};

Praktični primeri

Nastavitev lastnosti samo za branje

Recimo, da imate vmesnik, ki predstavlja uporabniški profil:

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

Ustvarite lahko nov tip, kjer so vse lastnosti samo za branje:

type ReadOnlyUserProfile = {
  readonly [K in keyof UserProfile]: UserProfile[K];
};

Sedaj bo ReadOnlyUserProfile imel enake lastnosti kot UserProfile, vendar bodo vse samo za branje.

Nastavitev lastnosti kot neobveznih

Podobno lahko vse lastnosti nastavite kot neobvezne:

type OptionalUserProfile = {
  [K in keyof UserProfile]?: UserProfile[K];
};

OptionalUserProfile bo imel vse lastnosti tipa UserProfile, vendar bo vsaka lastnost neobvezna.

Spreminjanje tipov lastnosti

Spremenite lahko tudi tip vsake lastnosti. Na primer, vse lastnosti lahko pretvorite v nize:

type StringifiedUserProfile = {
  [K in keyof UserProfile]: string;
};

V tem primeru bodo vse lastnosti v StringifiedUserProfile tipa string.

Kaj so pogojni tipi?

Pogojni tipi vam omogočajo definiranje tipov, ki so odvisni od pogoja. Omogočajo izražanje odnosov med tipi glede na to, ali tip izpolnjuje določeno omejitev. To je podobno ternarnemu operatorju v JavaScriptu, vendar za tipe.

Osnovna sintaksa

Sintaksa za pogojni tip je naslednja:

T extends U ? X : Y

Praktični primeri

Ugotavljanje, ali je tip niz

Ustvarimo tip, ki vrne string, če je vhodni tip niz, sicer pa number:

type StringOrNumber<T> = T extends string ? string : number;

type Result1 = StringOrNumber<string>;  // string
type Result2 = StringOrNumber<number>;  // number
type Result3 = StringOrNumber<boolean>; // number

Izločanje tipa iz unije

Pogojne tipe lahko uporabite za izločanje določenega tipa iz unijskega tipa. Na primer, za izločanje tipov, ki niso null:

type NonNullable<T> = T extends null | undefined ? never : T;

type Result4 = NonNullable<string | null | undefined>; // string

Tukaj, če je T null ali undefined, postane tip never, ki ga nato TypeScriptova poenostavitev unijskih tipov izloči.

Sklepanje (Infer) tipov

Pogojne tipe lahko uporabimo tudi za sklepanje o tipih z uporabo ključne besede infer. To vam omogoča, da iz bolj kompleksne strukture tipa izluščite tip.

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

function myFunction(x: number): string {
  return x.toString();
}

type Result5 = ReturnType<typeof myFunction>; // string

V tem primeru ReturnType izlušči povratni tip funkcije. Preveri, ali je T funkcija, ki sprejme poljubne argumente in vrne tip R. Če je, vrne R; sicer vrne any.

Kombiniranje preslikanih in pogojnih tipov

Prava moč preslikanih in pogojnih tipov se pokaže, ko jih kombiniramo. To omogoča ustvarjanje zelo prilagodljivih in izraznih transformacij tipov.

Primer: Globoki Readonly (Deep Readonly)

Pogost primer uporabe je ustvarjanje tipa, ki naredi vse lastnosti objekta, vključno z gnezdenimi lastnostmi, samo za branje. To lahko dosežemo z rekurzivnim pogojnim tipom.

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

interface Company {
  name: string;
  address: {
    street: string;
    city: string;
  };
}

type ReadonlyCompany = DeepReadonly<Company>;

Tukaj DeepReadonly rekurzivno uporabi modifikator readonly na vse lastnosti in njihove gnezdene lastnosti. Če je lastnost objekt, rekurzivno pokliče DeepReadonly na tem objektu. Sicer pa preprosto uporabi modifikator readonly na lastnosti.

Primer: Filtriranje lastnosti po tipu

Recimo, da želite ustvariti tip, ki vključuje samo lastnosti določenega tipa. To lahko dosežete s kombinacijo preslikanih in pogojnih tipov.

type FilterByType<T, U> = {
  [K in keyof T as T[K] extends U ? K : never]: T[K];
};

interface Person {
  name: string;
  age: number;
  isEmployed: boolean;
}

type StringProperties = FilterByType<Person, string>; // { name: string; }

type NonStringProperties = Omit<Person, keyof StringProperties>;

V tem primeru FilterByType iterira čez lastnosti T in preverja, ali tip vsake lastnosti razširja U. Če ga, vključi lastnost v končni tip; sicer jo izključi s preslikavo ključa v never. Upoštevajte uporabo "as" za preslikavo ključev. Nato uporabimo `Omit` in `keyof StringProperties` za odstranitev lastnosti tipa string iz prvotnega vmesnika.

Napredni primeri uporabe in vzorci

Poleg osnovnih primerov se lahko preslikani in pogojni tipi uporabljajo v bolj naprednih scenarijih za ustvarjanje zelo prilagodljivih in tipsko varnih aplikacij.

Distributivni pogojni tipi

Pogojni tipi so distributivni, kadar je preverjani tip unijski tip. To pomeni, da se pogoj uporabi za vsakega člana unije posebej, rezultati pa se nato združijo v nov unijski tip.

type ToArray<T> = T extends any ? T[] : never;

type Result6 = ToArray<string | number>; // string[] | number[]

V tem primeru se ToArray uporabi za vsakega člana unije string | number posebej, kar rezultira v string[] | number[]. Če pogoj ne bi bil distributiven, bi bil rezultat (string | number)[].

Uporaba pomožnih tipov (Utility Types)

TypeScript ponuja več vgrajenih pomožnih tipov, ki izkoriščajo preslikane in pogojne tipe. Te pomožne tipe lahko uporabimo kot gradnike za bolj kompleksne transformacije tipov.

Ti pomožni tipi so močna orodja, ki lahko poenostavijo kompleksne manipulacije s tipi. Na primer, lahko kombinirate Pick in Partial, da ustvarite tip, ki naredi samo določene lastnosti neobvezne:

type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

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

type OptionalDescriptionProduct = Optional<Product, "description">;

V tem primeru ima OptionalDescriptionProduct vse lastnosti Product, vendar je lastnost description neobvezna.

Uporaba tipov predlog nizov (Template Literal Types)

Tipi predlog nizov vam omogočajo ustvarjanje tipov na podlagi nizovnih literalov. Uporabite jih lahko v kombinaciji s preslikanimi in pogojnimi tipi za ustvarjanje dinamičnih in izraznih transformacij tipov. Na primer, lahko ustvarite tip, ki vsem imenom lastnosti doda določen predpono:

type Prefix<T, P extends string> = {
  [K in keyof T as `${P}${string & K}`]: T[K];
};

interface Settings {
  apiUrl: string;
  timeout: number;
}

type PrefixedSettings = Prefix<Settings, "data_">;

V tem primeru bo PrefixedSettings imel lastnosti data_apiUrl in data_timeout.

Najboljše prakse in premisleki

Zaključek

Preslikani tipi (Mapped Types) in Pogojni tipi (Conditional Types) so zmogljive funkcije v TypeScriptu, ki vam omogočajo ustvarjanje zelo prilagodljivih in izraznih transformacij tipov. Z obvladovanjem teh konceptov lahko izboljšate tipsko varnost, vzdržljivost in splošno kakovost vaših aplikacij v TypeScriptu. Od preprostih transformacij, kot je nastavljanje lastnosti na neobvezne ali samo za branje, do kompleksnih rekurzivnih transformacij in pogojne logike, te funkcije zagotavljajo orodja, ki jih potrebujete za gradnjo robustnih in razširljivih aplikacij. Nadaljujte z raziskovanjem in eksperimentiranjem s temi funkcijami, da odklenete njihov polni potencial in postanete bolj usposobljen razvijalec TypeScripta.

Ko nadaljujete svojo pot s TypeScriptom, ne pozabite izkoristiti bogastva razpoložljivih virov, vključno z uradno dokumentacijo TypeScripta, spletnimi skupnostmi in odprtokodnimi projekti. Sprejmite moč preslikanih in pogojnih tipov in dobro boste opremljeni za reševanje tudi najzahtevnejših problemov, povezanih s tipi.