Avastage TypeScripti võimsus täiustatud tingimuslike ja vastendatud tüüpide abil. Looge paindlikke, tüübikindlaid rakendusi, mis kohanduvad keerukate andmestruktuuridega.
TypeScripti täiustatud mustrid: tingimuslike ja vastendatud tüüpide meisterlikkus
TypeScripti võimsus peitub selle võimes pakkuda tugevat tüüpimist, mis võimaldab teil vigu varakult avastada ja kirjutada hooldatavamat koodi. Kuigi põhitüübid nagu string
, number
ja boolean
on fundamentaalsed, avavad TypeScripti täiustatud funktsioonid nagu tingimuslikud ja vastendatud tüübid uue paindlikkuse ja tüübikindluse dimensiooni. See põhjalik juhend süveneb nendesse võimsatesse kontseptsioonidesse, andes teile teadmised tõeliselt dünaamiliste ja kohandatavate TypeScripti rakenduste loomiseks.
Mis on tingimuslikud tüübid?
Tingimuslikud tüübid võimaldavad teil määratleda tüüpe, mis sõltuvad tingimusest, sarnaselt JavaScripti kolmekomponendilise operaatoriga (condition ? trueValue : falseValue
). Need võimaldavad teil väljendada keerulisi tüübisuhteid selle põhjal, kas tüüp vastab konkreetsele piirangule.
Süntaks
Tingimusliku tüübi põhisüntaks on:
T extends U ? X : Y
T
: kontrollitav tüüp.U
: tüüp, millega võrreldakse.extends
: võtmesõna, mis näitab alamtüübi suhet.X
: tüüp, mida kasutatakse, kuiT
on omistatav tüübileU
.Y
: tüüp, mida kasutatakse, kuiT
ei ole omistatav tüübileU
.
Sisuliselt, kui T extends U
väärtus on tõene, lahendatakse tüüp kui X
; vastasel juhul lahendatakse see kui Y
.
Praktilised näited
1. Funktsiooni parameetri tüübi määramine
Oletame, et soovite luua tüübi, mis määrab, kas funktsiooni parameeter on sõne või number:
type ParamType<T> = T extends string ? string : number;
function processValue(value: ParamType<string | number>): void {
if (typeof value === "string") {
console.log("Väärtus on sõne:", value);
} else {
console.log("Väärtus on number:", value);
}
}
processValue("hello"); // Väljund: Väärtus on sõne: hello
processValue(123); // Väljund: Väärtus on number: 123
Selles näites on ParamType<T>
tingimuslik tüüp. Kui T
on sõne, lahendatakse tüüp kui string
; vastasel juhul lahendatakse see kui number
. Funktsioon processValue
aktsepteerib selle tingimusliku tüübi põhjal kas sõne või numbri.
2. Tagastustüübi eraldamine sisendtüübi põhjal
Kujutage ette stsenaariumi, kus teil on funktsioon, mis tagastab sisendist olenevalt erinevaid tüüpe. Tingimuslikud tüübid aitavad teil määratleda õige tagastustüübi:
interface StringProcessor {
process(input: string): number;
}
interface NumberProcessor {
process(input: number): string;
}
type Processor<T> = T extends string ? StringProcessor : NumberProcessor;
function createProcessor<T extends string | number>(input: T): Processor<T> {
if (typeof input === "string") {
return { process: (input: string) => input.length } as Processor<T>;
} else {
return { process: (input: number) => input.toString() } as Processor<T>;
}
}
const stringProcessor = createProcessor("example");
const numberProcessor = createProcessor(42);
console.log(stringProcessor.process("example")); // Väljund: 7
console.log(numberProcessor.process(42)); // Väljund: "42"
Siin valib tüüp Processor<T>
tingimuslikult kas StringProcessor
või NumberProcessor
vastavalt sisendi tüübile. See tagab, et funktsioon createProcessor
tagastab õiget tüüpi protsessori objekti.
3. Eristatud ühendid
Tingimuslikud tüübid on eriti võimsad eristatud ühenditega töötamisel. Eristatud ühend on ühendtüüp, kus igal liikmel on ühine, singleton-tüüpi omadus (diskriminant). See võimaldab teil tüüpi kitsendada selle omaduse väärtuse põhjal.
interface Square {
kind: "square";
size: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Circle;
type Area<T extends Shape> = T extends { kind: "square" } ? number : string;
function calculateArea(shape: Shape): Area<typeof shape> {
if (shape.kind === "square") {
return shape.size * shape.size;
} else {
return Math.PI * shape.radius * shape.radius;
}
}
const mySquare: Square = { kind: "square", size: 5 };
const myCircle: Circle = { kind: "circle", radius: 3 };
console.log(calculateArea(mySquare)); // Väljund: 25
console.log(calculateArea(myCircle)); // Väljund: 28.274333882308138
Selles näites on Shape
tüüp eristatud ühend. Tüüp Area<T>
kasutab tingimuslikku tüüpi, et määrata, kas kujund on ruut või ring, tagastades ruutude puhul number
ja ringide puhul string
(kuigi reaalses stsenaariumis sooviksite tõenäoliselt ühtseid tagastustüüpe, demonstreerib see põhimõtet).
Põhilised järeldused tingimuslike tüüpide kohta
- Võimaldavad määratleda tüüpe tingimuste alusel.
- Parandavad tüübikindlust, väljendades keerulisi tüübisuhteid.
- On kasulikud funktsioonide parameetrite, tagastustüüpide ja eristatud ühenditega töötamisel.
Mis on vastendatud tüübid?
Vastendatud tüübid pakuvad võimalust olemasolevate tüüpide teisendamiseks, vastendades nende omadusi. Need võimaldavad teil luua uusi tüüpe teise tüübi omaduste põhjal, rakendades muudatusi, näiteks muutes omadusi valikuliseks, kirjutuskaitstuks või muutes nende tüüpe.
Süntaks
Vastendatud tüübi üldine süntaks on:
type NewType<T> = {
[K in keyof T]: ModifiedType;
};
T
: sisendtüüp.keyof T
: tüübioperaator, mis tagastab kõigi tüübiT
omaduste võtmete ühendi.K in keyof T
: itereerib üle iga võtmekeyof T
-s, omistades iga võtme tüübimuutujaleK
.ModifiedType
: tüüp, millele iga omadus vastendatakse. See võib sisaldada tingimuslikke tüüpe või muid tüübimuutusi.
Praktilised näited
1. Omaduste muutmine valikuliseks
Saate kasutada vastendatud tüüpi, et muuta kõik olemasoleva tüübi omadused valikuliseks:
interface User {
id: number;
name: string;
email: string;
}
type PartialUser = {
[K in keyof User]?: User[K];
};
const partialUser: PartialUser = {
name: "John Doe",
}; // Kehtiv, kuna 'id' ja 'email' on valikulised
Siin on PartialUser
vastendatud tüüp, mis itereerib üle liidese User
võtmete. Iga võtme K
puhul muudab see omaduse valikuliseks, lisades ?
modifikaatori. User[K]
hangib omaduse K
tüübi liidesest User
.
2. Omaduste muutmine kirjutuskaitstuks
Sarnaselt saate muuta kõik olemasoleva tüübi omadused kirjutuskaitstuks:
interface Product {
id: number;
name: string;
price: number;
}
type ReadonlyProduct = {
readonly [K in keyof Product]: Product[K];
};
const readonlyProduct: ReadonlyProduct = {
id: 123,
name: "Example Product",
price: 25.00,
};
// readonlyProduct.price = 30.00; // Viga: Ei saa omistada väärtust 'price'-le, sest see on kirjutuskaitstud omadus.
Sel juhul on ReadonlyProduct
vastendatud tüüp, mis lisab readonly
modifikaatori igale liidese Product
omadusele.
3. Omaduste tüüpide teisendamine
Vastendatud tüüpe saab kasutada ka omaduste tüüpide teisendamiseks. Näiteks saate luua tüübi, mis teisendab kõik sõne-tüüpi omadused numbriteks:
interface Config {
apiUrl: string;
timeout: string;
maxRetries: number;
}
type NumericConfig = {
[K in keyof Config]: Config[K] extends string ? number : Config[K];
};
const numericConfig: NumericConfig = {
apiUrl: 123, // Peab olema number vastenduse tõttu
timeout: 456, // Peab olema number vastenduse tõttu
maxRetries: 3,
};
See näide demonstreerib tingimusliku tüübi kasutamist vastendatud tüübi sees. Iga omaduse K
puhul kontrollib see, kas Config[K]
tüüp on sõne. Kui on, vastendatakse tüüp number
-ile; vastasel juhul jääb see muutmata.
4. Võtmete ümber vastendamine (alates TypeScript 4.1-st)
TypeScript 4.1 tõi sisse võimaluse vastendatud tüüpide sees võtmeid ümber vastendada, kasutades as
võtmesõna. See võimaldab teil luua uusi tüüpe erinevate omaduste nimedega, mis põhinevad algsel tüübil.
interface Event {
eventId: string;
eventName: string;
eventDate: Date;
}
type TransformedEvent = {
[K in keyof Event as `new${Capitalize<string&K>}`]: Event[K];
};
// Tulemus:
// {
// newEventId: string;
// newEventName: string;
// newEventDate: Date;
// }
//Capitalize funktsioon esimese tähe suurtäheks muutmiseks
type Capitalize<S extends string> = Uppercase<string&S> extends never ? string : `$Capitalize<S>`;
//Kasutamine reaalse objektiga
const myEvent: TransformedEvent = {
newEventId: "123",
newEventName: "New Name",
newEventDate: new Date()
};
Siin vastendab TransformedEvent
tüüp iga võtme K
uueks võtmeks, millele on lisatud eesliide "new" ja mis on suurtähega. Abistav funktsioon `Capitalize` tagab, et võtme esimene täht on suurtäht. Ristmik string & K
tagab, et tegeleme ainult sõne-tüüpi võtmetega ja saame K-st õige literaaltüübi.
Võtmete ümber vastendamine avab võimsaid võimalusi tüüpide teisendamiseks ja kohandamiseks vastavalt konkreetsetele vajadustele. See võimaldab teil võtmeid ümber nimetada, filtreerida või muuta keerulise loogika alusel.
Põhilised järeldused vastendatud tüüpide kohta
- Võimaldavad teisendada olemasolevaid tüüpe, vastendades nende omadusi.
- Lubavad muuta omadusi valikuliseks, kirjutuskaitstuks või muuta nende tüüpe.
- On kasulikud uute tüüpide loomisel teise tüübi omaduste põhjal.
- Võtmete ümber vastendamine (lisatud TypeScript 4.1-s) pakub veelgi suuremat paindlikkust tüübimuutustes.
Tingimuslike ja vastendatud tüüpide kombineerimine
Tingimuslike ja vastendatud tüüpide tegelik võimsus avaldub nende kombineerimisel. See võimaldab teil luua väga paindlikke ja väljendusrikkaid tüübimääratlusi, mis suudavad kohaneda paljude erinevate stsenaariumitega.
Näide: Omaduste filtreerimine tüübi järgi
Oletame, et soovite luua tüübi, mis filtreerib objekti omadusi nende tüübi alusel. Näiteks võite soovida objektist eraldada ainult sõne-tüüpi omadused.
interface Data {
name: string;
age: number;
city: string;
country: string;
isEmployed: boolean;
}
type StringProperties<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
type StringData = StringProperties<Data>;
// Tulemus:
// {
// name: string;
// city: string;
// country: string;
// }
const stringData: StringData = {
name: "John",
city: "New York",
country: "USA",
};
Selles näites kasutab StringProperties<T>
tüüp vastendatud tüüpi koos võtmete ümber vastendamise ja tingimusliku tüübiga. Iga omaduse K
puhul kontrollib see, kas T[K]
tüüp on sõne. Kui on, jäetakse võti alles; vastasel juhul vastendatakse see never
-ile, mis eemaldab selle tõhusalt. never
vastendatud tüübi võtmena eemaldab selle tulemuseks olevast tüübist. See tagab, et StringData
tüüpi kaasatakse ainult sõne-tüüpi omadused.
Abistavad tüübid TypeScriptis
TypeScript pakub mitmeid sisseehitatud abistavaid tüüpe, mis kasutavad tingimuslikke ja vastendatud tüüpe tavaliste tüübimuutuste tegemiseks. Nende abistavate tüüpide mõistmine võib teie koodi oluliselt lihtsustada ja parandada tüübikindlust.
Levinud abistavad tüübid
Partial<T>
: Muudab kõikT
omadused valikuliseks.Readonly<T>
: Muudab kõikT
omadused kirjutuskaitstuks.Required<T>
: Muudab kõikT
omadused kohustuslikuks (eemaldab?
modifikaatori).Pick<T, K extends keyof T>
: Valib hulgastT
omaduste komplektiK
.Omit<T, K extends keyof T>
: Eemaldab hulgastT
omaduste komplektiK
.Record<K extends keyof any, T>
: Konstrueerib tüübi omaduste komplektigaK
, mille tüüp onT
.Exclude<T, U>
: Välistab hulgastT
kõik tüübid, mis on omistatavadU
-le.Extract<T, U>
: Eraldab hulgastT
kõik tüübid, mis on omistatavadU
-le.NonNullable<T>
: Välistabnull
jaundefined
hulgastT
.Parameters<T>
: Hangib funktsioonitüübiT
parameetrid ennikuna.ReturnType<T>
: Hangib funktsioonitüübiT
tagastustüübi.InstanceType<T>
: Hangib konstruktorfunktsiooni tüübiT
instantsi tüübi.ThisType<T>
: Toimib kontekstipõhisethis
-tüübi markerina.
Need abistavad tüübid on ehitatud tingimuslike ja vastendatud tüüpide abil, mis demonstreerib nende täiustatud TypeScripti funktsioonide võimsust ja paindlikkust. Näiteks on Partial<T>
määratletud järgmiselt:
type Partial<T> = {
[P in keyof T]?: T[P];
};
Tingimuslike ja vastendatud tüüpide kasutamise parimad tavad
Kuigi tingimuslikud ja vastendatud tüübid on võimsad, võivad need hoolika kasutamiseta muuta teie koodi keerulisemaks. Siin on mõned parimad tavad, mida meeles pidada:
- Hoidke see lihtsana: Vältige liiga keerulisi tingimuslikke ja vastendatud tüüpe. Kui tüübimääratlus muutub liiga keeruliseks, kaaluge selle jagamist väiksemateks, paremini hallatavateks osadeks.
- Kasutage tähendusrikkaid nimesid: Andke oma tingimuslikele ja vastendatud tüüpidele kirjeldavad nimed, mis näitavad selgelt nende eesmärki.
- Dokumenteerige oma tüübid: Lisage kommentaare, et selgitada oma tingimuslike ja vastendatud tüüpide loogikat, eriti kui need on keerulised.
- Kasutage abistavaid tüüpe: Enne kohandatud tingimusliku või vastendatud tüübi loomist kontrollige, kas sisseehitatud abistav tüüp suudab saavutada sama tulemuse.
- Testige oma tüüpe: Veenduge, et teie tingimuslikud ja vastendatud tüübid käituksid ootuspäraselt, kirjutades ühikuteste, mis katavad erinevaid stsenaariume.
- Arvestage jõudlusega: Keerulised tüübiarvutused võivad mõjutada kompileerimisaega. Olge teadlik oma tüübimääratluste jõudlusmõjudest.
Kokkuvõte
Tingimuslikud ja vastendatud tüübid on TypeScripti meisterlikkuse saavutamiseks hädavajalikud tööriistad. Need võimaldavad teil luua väga paindlikke, tüübikindlaid ja hooldatavaid rakendusi, mis kohanduvad keerukate andmestruktuuride ja dünaamiliste nõuetega. Mõistes ja rakendades selles juhendis käsitletud kontseptsioone, saate avada TypeScripti täieliku potentsiaali ja kirjutada robustsemat ning skaleeritavamat koodi. TypeScripti edasi uurides ärge unustage katsetada erinevaid tingimuslike ja vastendatud tüüpide kombinatsioone, et avastada uusi viise keeruliste tüüpimisprobleemide lahendamiseks. Võimalused on tõeliselt lõputud.