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;
};
T
: Vhodni tip, ki ga želite preslikati.K in keyof T
: Iterira čez vsak ključ v vhodnem tipuT
.keyof T
ustvari unijo vseh imen lastnosti vT
,K
pa predstavlja vsak posamezen ključ med iteracijo.Transformation
: Transformacija, ki jo želite uporabiti na vsaki lastnosti. To je lahko dodajanje modifikatorja (kot stareadonly
ali?
), sprememba tipa ali kaj drugega.
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
T
: Tip, ki se preverja.U
: Tip, ki gaT
razširja (pogoj).X
: Tip, ki se vrne, čeT
razširjaU
(pogoj je resničen).Y
: Tip, ki se vrne, čeT
ne razširjaU
(pogoj je neresničen).
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.
Partial<T>
: Naredi vse lastnostiT
neobvezne.Required<T>
: Naredi vse lastnostiT
obvezne.Readonly<T>
: Naredi vse lastnostiT
samo za branje.Pick<T, K>
: Izbere nabor lastnostiK
izT
.Omit<T, K>
: Odstrani nabor lastnostiK
izT
.Record<K, T>
: Zgradi tip z naborom lastnostiK
tipaT
.Exclude<T, U>
: IzT
izključi vse tipe, ki so dodeljiviU
.Extract<T, U>
: IzT
izlušči vse tipe, ki so dodeljiviU
.NonNullable<T>
: IzT
izključinull
inundefined
.Parameters<T>
: Pridobi parametre funkcijskega tipaT
.ReturnType<T>
: Pridobi povratni tip funkcijskega tipaT
.InstanceType<T>
: Pridobi tip instance konstruktorske funkcije tipaT
.
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
- Ohranite preprostost: Čeprav so preslikani in pogojni tipi močni, lahko tudi zapletejo vašo kodo. Poskusite ohraniti vaše transformacije tipov čim bolj preproste.
- Uporabljajte pomožne tipe: Kadar koli je mogoče, izkoristite vgrajene pomožne tipe TypeScripta. So dobro preizkušeni in lahko poenostavijo vašo kodo.
- Dokumentirajte svoje tipe: Jasno dokumentirajte svoje transformacije tipov, še posebej, če so kompleksne. To bo pomagalo drugim razvijalcem razumeti vašo kodo.
- Testirajte svoje tipe: Uporabite TypeScriptovo preverjanje tipov, da zagotovite, da vaše transformacije tipov delujejo, kot je pričakovano. Lahko napišete enotske teste za preverjanje obnašanja vaših tipov.
- Upoštevajte zmogljivost: Kompleksne transformacije tipov lahko vplivajo na zmogljivost vašega prevajalnika TypeScript. Bodite pozorni na kompleksnost vaših tipov in se izogibajte nepotrebnim izračunom.
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.