Den andre opplæringen i vår TypeScript for Beginners-serie fokuserte på grunnleggende datatyper som er tilgjengelige i TypeScript. Typekontrollen i TypeScript lar oss sørge for at variablene i koden vår kun har bestemte typer verdier som er tildelt dem. På denne måten kan vi unngå mange feil mens du skriver kode fordi IDE vil kunne fortelle oss når vi utfører en operasjon på en type som den ikke støtter. Dette gjør at type sjekker en av de beste funksjonene til TypeScript.
I denne opplæringen vil vi fokusere på et annet viktig trekk ved denne språkgenerikken. Med generics gjør TypeScript deg til å skrive kode som kan fungere på en rekke datatyper i stedet for å være begrenset til en enkelt. Du vil lære om behovet for generikk i detalj og hvordan det er bedre enn å bare bruke noen
datatype tilgjengelig i TypeScript.
Hvis du ikke er kjent med generikk, kan du kanskje lure på hvorfor vi trenger dem i det hele tatt. I denne delen vil jeg svare på dette spørsmålet for deg. La oss begynne med å skrive en funksjon som returnerer et tilfeldig element fra en rekke tall.
funksjonen randomIntElem (theArray: tall []): tall la randomIndex = Math.floor (Math.random () * theArray.length); return theArray [randomIndex]; la posisjoner: tall [] = [103, 458, 472, 458]; la randomPosition: number = randomIntElem (stillinger);
De randomElem
funksjonen vi nettopp har definert, tar en rekke tall som sin eneste parameter. Funksjonens returtype er også angitt som et nummer. Vi bruker Math.random ()
funksjon for å returnere et flytende punkt-tilfeldig tall mellom 0 og 1. Multiplisere det med lengden på et gitt array og anrop Math.floor ()
på resultatet gir oss en tilfeldig indeks. Når vi har tilfeldige indekser, returnerer vi elementet til den aktuelle indeksen.
Noen ganger senere, la oss si at du trenger å få et tilfeldig strengelement fra en rekke strenger. På dette punktet kan du bestemme deg for å opprette en annen funksjon som spesifikt retter seg til strenger.
funksjon randomStrElem (theArray: string []): streng la randomIndex = Math.floor (Math.random () * theArray.length); return theArray [randomIndex]; la farger: streng [] = ['violet', 'indigo', 'blå', 'grønn']; la randomColor: string = randomStrElem (farger);
Hva om du må velge et tilfeldig element fra en rekke grensesnitt som du definerte? Å lage en ny funksjon hver gang du vil få et tilfeldig element fra en rekke ulike objekter, er ikke mulig.
En løsning for dette problemet er å angi typen av array-parametere som sendes til funksjonene som noen[]
. På denne måten kan du bare skrive din funksjon bare en gang, og den vil fungere med en rekke av alle typer.
funksjon randomElem (theArray: any []): any let randomIndex = Math.floor (Math.random () * theArray.length); return theArray [randomIndex]; la stillinger = [103, 458, 472, 458]; la randomPosition = randomElem (stillinger); la farger = ['violet', 'indigo', 'blå', 'grønn']; la randomColor = randomElem (farger);
Som du kan se, kan vi bruke funksjonen ovenfor for å få tilfeldige stillinger samt tilfeldige farger. Et stort problem med denne løsningen er at du vil miste informasjonen om typen verdi som blir returnert.
Tidligere var vi sikre på at randomPosition
ville være et tall og random
ville være en streng. Dette hjalp oss med å bruke disse verdiene tilsvarende. Nå, alt vi vet er at det returnerte elementet kunne være av noe slag. I koden ovenfor kan vi spesifisere typen av random
å være en Nummer
og fortsatt ikke få noen feil.
// Denne koden vil kompilere uten en feil. la farger: streng [] = ['violet', 'indigo', 'blå', 'grønn']; la randomColor: number = randomElem (farger);
En bedre løsning for å unngå kodeduplisering mens du fremdeles beholder typen informasjon, er å bruke generikk. Her er en generisk funksjon som returnerer tilfeldige elementer fra en matrise.
funksjon randomElem(theArray: T []): T let randomIndex = Math.floor (Math.random () * theArray.length); return theArray [randomIndex]; la farger: streng [] = ['violet', 'indigo', 'blå', 'grønn']; la randomColor: streng = randomElem (farger);
Nå får jeg en feil hvis jeg prøver å endre type random
fra string
til Nummer
. Dette viser at bruk av generikk er mye sikrere enn å bruke noen
skriv inn slike situasjoner.
Den forrige delen diskuterte hvordan du kan bruke generikk i stedet for noen
skriv inn for å skrive en enkelt funksjon og unngå å ofre fordelene med typekontroll. Et problem med den generiske funksjonen som vi har skrevet i forrige avsnitt er at TypeScript ikke lar oss utføre mange operasjoner på variablene som sendes til den.
Dette skyldes at TypeScript ikke kan gjøre noen antagelser om typen variabel som vil bli overført til vår generiske funksjon på forhånd. Som et resultat kan vår generiske funksjon bare bruke de operasjonene som gjelder for alle datatyper. Følgende eksempel skal gjøre dette konseptet tydeligere.
funksjon removeChar (theString: streng, theChar: streng): streng la theRegex = ny RegExp (theChar, "gi"); returner theString.replace (theRegex, ");
Ovennevnte funksjon vil fjerne alle forekomster av det angitte tegnet fra den oppgitte strengen. Du vil kanskje lage en generell versjon av denne funksjonen, slik at du også kan fjerne bestemte siffer fra et gitt nummer, så vel som tegn fra en streng. Her er den tilsvarende generiske funksjonen.
funksjon removeIt(theInput: T, theIt: strengen): T la theRegex = ny RegExp (theIt, "gi"); return theInput.replace (theRegex, ");
De removeChar
funksjonen viste deg ikke en feil. Men hvis du bruker erstatte
innsiden fjern det
,TypeScript vil fortelle deg det erstatte
finnes ikke for type 'T'. Dette skyldes at TypeScript ikke lenger kan anta det theInput
kommer til å bli en streng.
Denne begrensningen ved bruk av forskjellige metoder i en generisk funksjon kan føre til at du tenker at begrepet generiske ikke kommer til å være til stor nytte etter alle. Det er ikke veldig mye du kan gjøre med en håndfull metoder som må gjelde på alle datatyper, slik at du kan bruke dem i en generisk funksjon.
En viktig ting du bør huske på dette tidspunktet er at du ikke generelt trenger å opprette funksjoner som skal brukes med alle typer datatyper. Det er mer vanlig å lage en funksjon som vil bli brukt med et bestemt sett eller spekter av datatyper. Denne begrensningen på datatyper gjør generiske funksjoner mye mer nyttige.
Den generiske fjern det
funksjon fra forrige seksjon viste en feil fordi erstatte
Metoden inne i det er ment å bli brukt med strenger, mens parametrene som sendes til den, kan ha en hvilken som helst datatype.
Du kan bruke strekker
søkeord for å begrense datatyper som sendes til en generell funksjon i TypeScript. derimot, strekker
er begrenset til bare grensesnitt og klasser. Dette betyr at de fleste generiske funksjoner du lager, vil ha parametere som utvider et grensesnitt eller en klasse.
Her er en generell funksjon som skriver ut navnet til folk, familiemedlemmer eller kjendiser som er sendt til den.
grensesnitt Mennesker navn: streng grensesnitt Familie navn: streng, alder: nummer, relasjon: streng grensesnitt Celebrity utvider folk yrke: streng funksjon utskriftsnavn(theInput: T): void console.log ('Mitt navn er $ theInput.name'); la serena: Celebrity = name: 'Serena Williams', yrke: 'Tennis Player' printName (serena);
I eksemplet ovenfor har vi definert tre grensesnitt, og hver av dem har a Navn
eiendom. Den generiske printname
funksjonen vi opprettet vil akseptere ethvert objekt som strekker seg Mennesker
. Med andre ord kan du enten sende en familie eller et kjendisobjekt til denne funksjonen, og den vil skrive ut navnet sitt uten noen klager. Du kan definere mange flere grensesnitt, og så lenge de har en Navn
eiendom, vil du kunne bruke printname
funksjon uten problem.
Dette var et veldig grunnleggende eksempel, men du kan skape mer nyttige generiske funksjoner når du er mer komfortabel med hele prosessen. For eksempel kan du opprette en generell funksjon som beregner totalverdien av forskjellige varer som er solgt i en gitt måned så lenge hvert element har en pris
eiendom for å lagre prisen og a selges
eiendom som lagrer antall solgte varer. Ved hjelp av generikk, vil du kunne bruke samme funksjon så lenge varene utvider det samme grensesnittet eller klassen.
I denne opplæringen har jeg forsøkt å dekke grunnleggende om generikk i TypeScript på en nybegynnerlig måte. Vi begynte artikkelen ved å diskutere behovet for generikk. Etter det lærte vi om den riktige måten å bruke generikk for å unngå kod duplisering uten å ofre typekontrollevnen. Når du forstår det grunnleggende som diskuteres her, kan du lese mer om generikk i den offisielle dokumentasjonen.
Hvis du har noen spørsmål knyttet til denne opplæringen, vil jeg gjerne svare på dem i kommentarene.