A medida que mecanografía está crecendo e gañando popularidade recentemente, máis e máis desenvolvedores de javascript aprecian a seguridade do tipo. A lista de funcións que ofrece Typescript é enorme e pode ser abrumadora, polo que nesta publicación, centrareime nunha delas que é fácil de entender e que ten un bo impacto práctico.
Comecemos cun exemplo. Imaxina que estás a desenvolver unha aplicación con moitos roles de usuario. É bastante común que unha aplicación sexa consumida por diferentes usuarios, non si? Os roles exactos non son realmente importantes aquí, pero digamos que son admin
, consumer
e guest
. No mecanografiado, podemos declarar os usuarios que teñen eses roles do seguinte xeito:
type Admin = {} type Consumer = {} type Guest = {}
Agora, imos considerar un conxunto de atributos que ten cada rol de usuario. Normalmente, son email
, firstName
e lastName
ou algo así. Pero, espera, probablemente os usuarios Guest
non os teñan (a fin de contas son convidados), así que deixemos este tipo baleiro polo momento.
type Admin = { firstName: string lastName: string email: string } type Consumer = { firstName: string lastName: string email: string } type Guest = {}
O usuario dunha aplicación só podería ter unha función. A forma de representar isto a través dos tipos é usar un tipo union
.
type User = Admin | Consumer | Guest
Os administradores son famosos polas súas habilidades exclusivas e, na nosa aplicación, poden convidar consumidores. Engademos un campo que indica cantas invitacións pode enviar un administrador.
type Admin = { firstName: string lastName: string email: string numberOfInvitesLeft: number // <-- added }
Para facer as cousas máis interesantes e máis próximas a unha aplicación real, imos engadir unha propiedade exclusiva dun tipo Consumer
.
type Consumer = { firstName: string lastName: string email: string premium: boolean // <-- added }
Este é un exemplo moi sinxelo e, en realidade, os usuarios poderían ter ducias de propiedades dispares, o que complica considerablemente a base de código cando precisa acceder a determinadas propiedades.
const doSomethingBasedOnRole = (user: User) => { // how do you check here that user is really an admin if (user) { // ...and do something with the `numberOfInvitesLeft` property? } }
Unha opción é comprobar a existencia do inmoble.
const doSomethingBasedOnRole = (user: User) => { if (user && user.numberOfInvitesLeft) { // safely access `numberOfInvitesLeft` property } }
Pero esta é unha solución tediosa e non escalable. E que facer cando `numberOfInvitesLeft` se converte nunha propiedade opcional?
Aquí é onde entran en xogo os tipos de sindicatos discriminados. Só necesitamos poñer un campo adicional en cada tipo de usuario indicando o rol.
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 }
Observe como estou poñendo unha cadea específica como tipo; isto chámase tipo literal de cadea . O que che dá isto é que agora podes usar operadores nativos da linguaxe JS, por exemplo, switch case
, if
, else
para discriminar o rol.
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 } }
O mesmo aplícase a unha declaración 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'." // } } }
Os beneficios dos tipos de unión discriminados son evidentes porque a comprobación de tipos baséase nunha propiedade de rol explícita e non en propiedades ad-hoc que poden ou non estar relacionadas cun usuario específico.