Monet kehittäjät ovat hämmentyneitä valitessaan TypeScript-rajapinnan tai tyypin välillä. Tämä johtuu luultavasti siitä, että ne ovat hyvin samankaltaisia pienin eroavaisuuksin.
Tarkastellaan joitakin järkeviä käytäntöjä ja oletusarvoja, samalla kun paljastetaan joitakin TypeScript-kielen piilotettuja helmiä ja vastataan kysymykseen: ”Pitäisikö minun käyttää rajapintaa vai tyyppiä?”
Kun olet valmis, tutustu toiseen artikkeliini TypeScript-rajapinnat vs. luokat!
Tässä on minun sääntöni: Käyttötapauksissa, kuten uusien tyyppien luomisessa esimerkiksi primitiivien, union-tyyppien ja tuplatyyppien avulla, käytän mieluummin type
-avainsanaa. Kaikessa muussa (objektit/matriisit) se on interface
.
interface
on erittäin hyödyllinen käsiteltäessä tietorakenteita, koska ne ovat hyvin visuaalinen esitys (vaikkakin niin on myös type
, tämä on tyypillisesti suosikkini). On täysin ok valita type
myös objekteille ja matriiseille.
Paljastetaan kuitenkin hieman lisää Types vs. Interfaces TypeScriptissä, jotta voit tehdä tietoisemman päätöksen.
Objects: Type vs Interface
Tyypillisesti määrittelisimme tietorakenteen mallintamaan tyypin aiottuja muuttujia ja funktion argumentteja vastaan. Useimmiten tietorakenne on joukko tai objekti, joka saattaa sisältää muutaman metodin.
Luotaan objekti rajapintana (suositeltava lähestymistapa):
interface Milkshake { name: string; price: number; getIngredients(): string;}
Tässä tapauksessa käytän mieluummin rajapintaa, koska on selvää, että kyseessä on rajapinta eikä muuttuja, jolle on määritetty dataa – hieno helppolukuisuusvoitto. Käytämme name
ja price
salliaksemme tietueiden asettamisen ja getIngredients
metodikutsuna.
🎉 Lataa se ilmaiseksi!
Oletko valmis menemään ForEachia pidemmälle? Luota edistyneisiin menetelmiin – Reduce, Find, Filter, Every, Some ja Map.
- Ymmärrä täysin, miten JavaScriptin tietorakenteita hallitaan muuttumattomilla operaatioilla
- 31 sivua syväluotaavaa syntaksia, reaalimaailman esimerkkejä, vinkkejä ja niksejä
- Kirjoita siistimpää ja paremmin jäsenneltyä ohjelmointilogiikkaa kolmessa tunnissa
Lisäbonuksena lähetämme sinulle myös ylimääräisiä herkkuja muutaman ylimääräisen sähköpostin poikki.
Kun verrataan tuota tyyppiin – se voidaan helposti sekoittaa varsinaiseksi objektiksi johtuen osoituksesta =
:
type Milkshake = { name: string; price: number; getIngredients(): string;};
Tämä on vain pieni mieltymykseni siihen, että valitsen tässä yhteydessä mieluummin interface
kuin käytän type
– mutta voit halutessasi vapaasti käyttää avainsanaa type
.
Kytkentä: Type vs Interface
Intersecting tarkoittaa yksinkertaisesti yhden tai useamman tyypin yhdistämistä! Tämä kuvio voidaan toteuttaa käyttämällä sekä interface
että type
.
Esitellään seuraavat rajapinnat, näytän sinulle, miten voimme leikata interface
ja type
:
interface MilkshakeProps { name: string; price: number;}interface MilkshakeMethods { getIngredients(): string;}
Liitännäisellä rajapinnalla leikataan käyttämällä extends
-avainsanaa. Käytän useita rajapintoja näyttääkseni, miten laajennamme (periytämme) lopulliseen Milkshake
-rajapintaan, joka sisältää kaikki muualla määritellyt ominaisuudet ja metodit:
// { name: string, price: number, getIngredients(): string }interface Milkshake extends MilkshakeProps, MilkshakeMethods {}
Voitamme nyt käyttää Milkshake
-rajapintaa missä tahansa, ja hyödymme siitä, että meillä on name
-, price
– ja getIngredients
-tiedot yhdessä rajapintaviittauksessa.
Tässä teemme saman type
:llä ja leikkaamme tyypit &
:n kautta:
// { name: string, price: number, getIngredients(): string }type Milkshake = MilkshakeProps & MilkshakeMethods;
Suosittelen käyttämään type
:aa interface
:n sijaan type
:aa, kun haluat leikata tyypit. extends
:n käyttäminen tuntuu hieman pitkäveteisemmältä eikä ole yhtä selkeää luettavaa, ja minusta tuntuu, että juuri tätä varten type
-avainsana on tehty.
On myös superhelppoa vain yhdistää useampia tyyppejä type
:lla. Minusta koodi on selkeämpää kuin extends
:n käyttäminen intefacen kanssa.
Interfacen käyttö on myös rajoitettua – type
-alasanaa voi käyttää monimutkaisemmille tyypeille, kuten tupleille, primitiiveille, unioille ja muille enemmän:
// { name: string, price: number, getIngredients(): string }type Milkshake = MilkshakeProps & { getIngredients(): string };
Primitiivit: Tyyppi vs rajapinta
Puhutaan primitiivisistä tyypeistä. Kyllä, merkkijonot, numerot jne. Voit määrittää primitiivisen tyypin vain type
aliakselle:
type MilkshakeName = string;interface Milkshake { name: MilkshakeName; price: number;}
Jos haluat käyttää primitiiviä, käytä type
. Rajapinnat eivät käy tässä vain yhdelle arvolle, koska syntaksi ei tue sitä.
🎉 Lataa se ilmaiseksi!
Oletko valmis menemään ForEachia pidemmälle? Luota edistyneisiin menetelmiin – Reduce, Find, Filter, Every, Some ja Map.
- Ymmärrä täysin, miten JavaScriptin tietorakenteita hallitaan muuttumattomilla operaatioilla
- 31 sivua syväluotaavaa syntaksia, reaalimaailman esimerkkejä, vinkkejä ja niksejä
- Kirjoita siistimpää ja paremmin jäsenneltyä ohjelmointilogiikkaa kolmessa tunnissa
Lisäbonuksena lähetämme sinulle myös ylimääräisiä herkkuja muutaman ylimääräisen sähköpostin poikki.
Useimmissa tapauksissa olisi kuitenkin helpompaa käyttää suoraan primitiivistä arvoa:
interface Milkshake { name: string; price: number;}
Älä monimutkaista koodiasi liikaa!
Luokat: Type vs Interface
Olitpa valinnut type
tai interface
, tapa jolla käytämme sitä luokan kanssa on sama:
type Size = { size: string};interface Milkshake { name: string; price: number; getIngredients(): string;}class Order implements Size, Milkshake { // Size size = 'large'; // Milkshake name = 'Vanilla'; price = 399; getIngredients() { return ; }}
Luokat eivät tue unionityyppien toteuttamista/laajentamista, koska niitä pidetään staattisina blueprinteinä. Tämä tarkoittaa sitä, että sinun täytyy olla erittäin selkeä jokaisesta toteuttamastasi tyypistä, koska se ei voi olla dynaaminen tai muuttua juuri nyt TypeScriptin rajoitusten vuoksi.
Opi lisää TypeScriptin rajapinnoista vs. luokat!
Funktiot: Type vs Interface
Tyypillisesti loisin funktion käyttämällä type
aliasta, koska useimmiten haluamme kirjoittaa anonyymin funktion:
type IngredientsFn = () => string;const getIngredients: IngredientsFn = () => ;
Jos kuitenkin interface
käyttäminen tähän olisi enemmän sinun tyylisi, tässä kerrotaan miten se tehdään:
interface IngredientsFn { () => string;}
Se vain tuntuu hieman vinksahtaneelta verrattuna type
:n käyttämiseen, mutta taas molemmat ovat täysin kelvollista TypeScriptiä, eikä koodin kääntämisessä ole eroa.
Milloin ei kannata käyttää Typea
Nyt kun olemme tutkineet erilaisia vertailuja ja suositeltavia lähestymistapoja, on aika puhua Declaration Mergingistä, TypeScriptin ominaisuudesta, joka koskee vain interface
:tä ja olisi syy valita interface
type
:n sijaan.
Tyyppien yhdistämiseksi type
:n avulla meidän täytyisi tehdä jotakin tällaista ja luoda uusi lopullinen type
:
type MilkshakeProps = { name: string; price: number;};type MilkshakeMethods = { getIngredients(): string;};type Milkshake = MilkshakeProps & MilkshakeMethods;
Meidän type Milkshake
on nyt MilkshakeProps
:n ja MilkshakeMethods
:n tyyppialias. Huomaa, että saavuttaaksemme tämän käyttäytymisen meidän on täytynyt luoda Milkshake
, jolloin saamme kolme yksittäistä tyyppialiasia.
Liitäntöjen kanssa on itse asiassa olemassa fiksumpi lähestymistapa (joidenkin mielestä ehkä liiankin fiksu), jota kutsutaan julistusten yhdistämiseksi.
Voidaan saavuttaa julistusten yhdistäminen yksinkertaisesti julistamalla sama interface
kahdesti samassa laajuudessa (tämä voi tapahtua joko tuomalla rajapinta toisesta moduulista tai julistamalla se paikallisesti toisen rajapinnan vieressä):
// declared once...interface Milkshake { name: string; price: number;}// declared again the same, it works!interface Milkshake { getIngredients(): string;}// { name: string, price: number, getIngredients(): string }const milkshake: Milkshake = { name: 'Banana', price: 399, getIngredients() {...}};
Milkshake sisältää nyt name
, price
ja getIngredients
! Onko ilmoitusten yhdistäminen kuitenkin hyvä asia? En rehellisesti sanottuna ole fani ja minusta tuntuu, että siitä voi olla enemmän haittaa kuin hyötyä. Koostaisin tyypit mieluummin type
:n kautta kuin käyttäisin julistusten yhdistämistä – mutta ainakin tiedät nyt tärkeimmät erot.
Johtopäätös
Se on siis siinä! Tärkeimmät erot tyyppien ja rajapintojen välillä TypeScriptissä.
Yhteenvetona, jossa on myös joitakin henkilökohtaisia mieltymyksiä, pitäytyisin interface
:ssä objekteille ja käyttäisin type
alias-avainsanaa uusien tyyppien kokoamiseen lennossa. Nämä uudet tyypit voisivat olla jopa rajapintoja tai muita tyyppejä, kuten tupleja, unioneita ja leikkaustyyppejä. Mahdollisuuksia on paljon, mutta ymmärtämällä lähestymistapoja voimme alkaa valita oikean työkalun.
Suurimmaksi osaksi rajapinnat ja tyypit ovat melko samanlaisia muutamia tässä käsiteltyjä eroja lukuun ottamatta. Toivottavasti nautit lukemisesta!
Jos olet tosissasi TypeScript-taitojesi suhteen, seuraava askeleesi on vilkaista TypeScript-kurssejani, ne opettavat sinulle täydet kielen perusteet yksityiskohtaisesti sekä monia edistyneempiä käyttötapauksia, joita tarvitset jokapäiväisessä TypeScript-kehityksessä!
Happy coding!