paint-brush
Η Δύναμη των Διακρινόμενων Ενώσεων στο TypeScriptμε@tokenvolt
230 αναγνώσεις

Η Δύναμη των Διακρινόμενων Ενώσεων στο TypeScript

με Oleksandr Khrustalov4m2024/10/05
Read on Terminal Reader

Πολύ μακρύ; Να διαβασω

Αυτή η ιστορία παρουσιάζει επισκόπηση των βασικών ενώσεων που γίνονται διακρίσεις στο TypeScrips. Τα χρησιμοποιώ αρκετά συχνά στην ανάπτυξή μου, οπότε θα δούμε ένα συγκεκριμένο παράδειγμα για το πώς να τα εφαρμόσω.
featured image - Η Δύναμη των Διακρινόμενων Ενώσεων στο TypeScript
Oleksandr Khrustalov HackerNoon profile picture

Δηλώνοντας το πρόβλημα

Καθώς το typescript αυξάνεται και κερδίζει δημοτικότητα πρόσφατα, όλο και περισσότεροι προγραμματιστές javascript εκτιμούν την ασφάλεια τύπου. Ο κατάλογος των χαρακτηριστικών που παρέχει το Typescript είναι τεράστιος και μπορεί να είναι συντριπτικός, επομένως σε αυτήν την ανάρτηση, θα επικεντρωθώ σε ένα από αυτά που είναι εύκολο να κατανοηθεί και έχει μια τακτοποιημένη πρακτική επίδραση.


Ας ξεκινήσουμε με ένα παράδειγμα. Φανταστείτε ότι αναπτύσσετε μια εφαρμογή με πολλούς ρόλους χρήστη. Είναι αρκετά συνηθισμένο μια εφαρμογή να καταναλώνεται από διαφορετικούς χρήστες, έτσι δεν είναι; Οι ακριβείς ρόλοι δεν είναι πραγματικά σημαντικοί εδώ, αλλά ας πούμε ότι είναι admin , consumer και guest . Στο typescript, μπορούμε να δηλώσουμε χρήστες που κατέχουν αυτούς τους ρόλους ως εξής:


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


Τώρα, ας εξετάσουμε ένα σύνολο χαρακτηριστικών που έχει κάθε ρόλος χρήστη. Συνήθως, είναι email , firstName και lastName ή κάτι τέτοιο. Αλλά, περιμένετε, οι Guest χρήστες πιθανότατα δεν θα τα έχουν αυτά (είναι φιλοξενούμενοι τελικά), οπότε ας αφήσουμε απλώς αυτόν τον τύπο κενό προς το παρόν.


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


Ο χρήστης μιας εφαρμογής θα μπορούσε να έχει μόνο έναν ρόλο. Ο τρόπος για να το αναπαραστήσετε αυτό μέσω τύπων είναι να χρησιμοποιήσετε έναν τύπο union .


 type User = Admin | Consumer | Guest


Οι διαχειριστές φημίζονται για τις αποκλειστικές τους ικανότητες και στην εφαρμογή μας μπορούν να προσκαλούν καταναλωτές. Ας προσθέσουμε ένα πεδίο που υποδεικνύει πόσες προσκλήσεις θα μπορούσε να στείλει ένας διαχειριστής.


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


Για να κάνουμε τα πράγματα πιο ενδιαφέροντα και πιο κοντά σε μια πραγματική εφαρμογή, ας προσθέσουμε ένα ακίνητο αποκλειστικά για έναν τύπο Consumer .


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


Αυτό είναι ένα πολύ απλό παράδειγμα και στην πραγματικότητα, οι χρήστες θα μπορούσαν να έχουν δεκάδες διαφορετικές ιδιότητες, γεγονός που περιπλέκει σημαντικά τη βάση κώδικα όταν χρειάζεται να αποκτήσετε πρόσβαση σε ορισμένες ιδιότητες.


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


Μια επιλογή είναι να ελέγξετε την ύπαρξη του ακινήτου.


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


Αλλά αυτή είναι μια κουραστική και όχι μια επεκτάσιμη λύση. Και τι να κάνετε όταν το "numberOfInvitesLeft" γίνει προαιρετική ιδιότητα;

Εισαγωγή των τύπων ένωσης που διακρίνονται

Εδώ μπαίνουν στο παιχνίδι οι τύποι συνδικάτων που διακρίνονται. Απλώς πρέπει να βάλουμε ένα πρόσθετο πεδίο σε κάθε τύπο χρήστη που υποδεικνύει το ρόλο.


 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 }


Παρατηρήστε πώς βάζω μια συγκεκριμένη συμβολοσειρά ως τύπο. Αυτό ονομάζεται κυριολεκτικός τύπος συμβολοσειράς . Αυτό που σας δίνει είναι ότι τώρα μπορείτε να χρησιμοποιήσετε εγγενείς τελεστές γλώσσας JS, π.χ., switch case , if , else για να κάνετε διάκριση στο ρόλο.


 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 } }


Το ίδιο ισχύει για μια δήλωση περίπτωσης διακόπτη.


 // ... 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'." // } } }


Τα πλεονεκτήματα των τύπων ένωσης που διακρίνονται είναι εμφανή επειδή ο έλεγχος τύπου βασίζεται σε ρητή ιδιότητα ρόλου και όχι σε ιδιότητες ad-hoc που μπορεί να σχετίζονται ή να μην σχετίζονται με έναν συγκεκριμένο χρήστη.