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ă?
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.