paint-brush
Puterea uniunilor discriminate în TypeScriptde@tokenvolt
242 lecturi

Puterea uniunilor discriminate în TypeScript

de Oleksandr Khrustalov4m2024/10/05
Read on Terminal Reader

Prea lung; A citi

Această poveste prezintă elementele de bază ale sindicatelor discriminate în TypeScrips. Le folosesc destul de des în dezvoltarea mea, așa că ne vom uita la un anumit exemplu despre cum să le aplicăm.
featured image - Puterea uniunilor discriminate în TypeScript
Oleksandr Khrustalov HackerNoon profile picture

Prezentarea problemei

Pe măsură ce dactilografia crește și câștigă popularitate recent, tot mai mulți dezvoltatori de javascript apreciază siguranța tipului. Lista de caracteristici oferite de Typescript este imensă și poate fi copleșitoare, așa că în această postare mă voi concentra pe una dintre ele care este ușor de înțeles și are un impact practic clar.


Să începem cu un exemplu. Imaginați-vă că dezvoltați o aplicație cu multe roluri de utilizator. Este destul de comun ca o aplicație să fie consumată de diferiți utilizatori, nu-i așa? Rolurile exacte nu sunt foarte importante aici, dar să presupunem că sunt admin , consumer și guest . La dactilografiat, putem declara utilizatorii care dețin aceste roluri după cum urmează:


 type Admin = {} type Consumer = {} type Guest = {}


Acum, să luăm în considerare un set de atribute pe care le are fiecare rol de utilizator. De obicei, acestea sunt email , firstName și lastName sau ceva de genul ăsta. Dar, stai, probabil că utilizatorii Guest nu le vor avea (la urma urmei sunt oaspeți), așa că să lăsăm acest tip gol pentru moment.


 type Admin = { firstName: string lastName: string email: string } type Consumer = { firstName: string lastName: string email: string } type Guest = {}


Utilizatorul unei aplicații poate avea un singur rol. Modul de a reprezenta acest lucru prin tipuri este de a folosi un tip union .


 type User = Admin | Consumer | Guest


Administratorii sunt renumiti pentru abilitățile lor exclusive, iar în aplicația noastră, ei sunt capabili să invite consumatorii. Să adăugăm un câmp care indică câte invitații ar putea trimite un administrator.


 type Admin = { firstName: string lastName: string email: string numberOfInvitesLeft: number // <-- added }


Pentru a face lucrurile mai interesante și mai aproape de o aplicație reală, să adăugăm o proprietate exclusivă unui tip Consumer .


 type Consumer = { firstName: string lastName: string email: string premium: boolean // <-- added }


Acesta este un exemplu foarte simplu și, în realitate, utilizatorii ar putea avea zeci de proprietăți disparate, ceea ce complică considerabil baza de cod atunci când trebuie să accesați anumite proprietăți.


 const doSomethingBasedOnRole = (user: User) => { // how do you check here that user is really an admin if (user) { // ...and do something with the `numberOfInvitesLeft` property? } }


O opțiune este să verificați existența proprietății.


 const doSomethingBasedOnRole = (user: User) => { if (user && user.numberOfInvitesLeft) { // safely access `numberOfInvitesLeft` property } }


Dar aceasta este o soluție plictisitoare și nu scalabilă. Și ce să faci când `numberOfInvitesLeft` devine o proprietate opțională?

Introducerea tipurilor de sindicate discriminate

Aici intră în joc tipurile de sindicat discriminate. Trebuie doar să punem un câmp suplimentar în fiecare tip de utilizator care indică rolul.


 type Admin = { firstName: string lastName: string email: string numberOfInvitesLeft: number role: "admin" // <-- added } type Consumer = { firstName: string lastName: string email: string role: "consumer" // <-- added } type Guest = { role: "guest" // <-- added }


Observați cum pun un anumit șir ca tip; acesta se numește tip literal șir . Ceea ce vă oferă acest lucru este că acum puteți utiliza operatori nativi în limbaj JS, de exemplu, switch case , if , else pentru a discrimina rolul.


 const user: Admin = { firstName: "John", lastName: "Smith", email: "[email protected]", numberOfInvitesLeft: 3, role: "admin", } const doSomethingBasedOnRole = (user: User) => { if (user.role === "admin") { // now typescript knows that INSIDE of this block user is of type `Admin` // now you can safely call `user.numberOfInvitesLeft` within this block } }


Același lucru este valabil și pentru o declarație switch case.


 // ... const doSomethingBasedOnRole = (user: User) => { switch (user.role) { case "admin": { // now typescript knows that INSIDE of this block user is of type `Admin` // now you can safely call `user.numberOfInvitesLeft` within this block } case "consumer": { // do something with a `Consumer` user // if you try to call `user.numberOfInvitesLeft` here, TS compiler errors in // // "Property 'numberOfInvitesLeft' does not exist on type 'Consumer'." // } } }


Beneficiile tipurilor de uniuni discriminate sunt evidente deoarece verificarea tipului se bazează pe proprietatea rolului explicit și nu pe proprietăți ad-hoc care ar putea sau nu să fie legate de un anumit utilizator.