Καθώς το 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 που μπορεί να σχετίζονται ή να μην σχετίζονται με έναν συγκεκριμένο χρήστη.