TypeScript – Rajapinnat

Rajapinta on rakenne, joka määrittelee sovelluksesi sopimuksen. Se määrittelee syntaksin, jota luokat noudattavat. Rajapinnasta johdettujen luokkien on noudatettava rajapintansa antamaa rakennetta.

TypeScript-kääntäjä ei muunna rajapintaa JavaScriptiksi. Se käyttää rajapintaa tyypintarkistukseen. Tämä tunnetaan myös nimellä ”ankkatyypitys” tai ”rakenteellinen alatyypitys”.

Liittymä määritellään avainsanalla interface, ja se voi sisältää ominaisuuksien ja metodien julistuksia funktiota tai nuolifunktiota käyttäen.

Esim: Rajapinta

Kopioi

interface IEmployee { empCode: number; empName: string; getSalary: (number) => number; // arrow function getManagerName(number): string; }

Yllä olevassa esimerkissä IEmployee -rajapinta sisältää kaksi ominaisuutta empCode ja empName. Se sisältää myös metodi-ilmoituksen getSalaray, jossa käytetään nuolifunktiota, joka sisältää yhden numeroparametrin ja numeron paluutyypin. Metodi getManagerName on deklaroitu käyttäen normaalia funktiota. Tämä tarkoittaa, että minkä tahansa IEmployee-tyyppisen objektin on määriteltävä nämä kaksi ominaisuutta ja kaksi metodia.

Interfacen käyttäminen tyyppinä

Interfacen avulla TypeScriptissä voidaan määritellä tyyppi ja myös toteuttaa se luokassa.

Seuraava rajapinta IEmployee määrittelee muuttujan tyypin.

Esimerkki: Rajapinta tyyppinä

Kopioi

interface KeyPair { key: number; value: string;}let kv1: KeyPair = { key:1, value:"Steve" }; // OKlet kv2: KeyPair = { key:1, val:"Steve" }; // Compiler Error: 'val' doesn't exist in type 'KeyPair'let kv3: KeyPair = { key:1, value:100 }; // Compiler Error: 

Yllä olevassa esimerkissä rajapinta KeyPair sisältää kaksi ominaisuutta key ja value. Muuttuja kv1 on ilmoitettu tyypiksi KeyPair. Sen on siis noudatettava samaa rakennetta kuin KeyPair. Se tarkoittaa, että muuttujaan kv1 voidaan liittää vain objekti, jonka ominaisuudet key ovat numerotyyppisiä ja value merkkijonotyyppisiä. TypeScript-kääntäjä näyttää virheen, jos ominaisuuksien nimet muuttuvat tai tietotyyppi on eri kuin KeyPair. Toinen muuttuja kv2 on myös ilmoitettu KeyPair-tyyppiseksi, mutta sille annettu arvo on val eikä value, joten tämä aiheuttaa virheen. Samalla tavalla kv3 määrittää ominaisuudelle value numeron, joten kääntäjä näyttää virheen. TypeScript käyttää siis rajapintaa varmistaakseen objektin oikean rakenteen.

Liittymä funktion tyyppinä

TypeScriptin rajapintaa käytetään myös funktion tyypin määrittelyyn. Näin varmistetaan funktion allekirjoitus.

Esimerkki: Function Type

Copy

interface KeyValueProcessor{ (key: number, value: string): void;};function addKeyValue(key:number, value:string):void { console.log('addKeyValue: key = ' + key + ', value = ' + value)}function updateKeyValue(key: number, value:string):void { console.log('updateKeyValue: key = '+ key + ', value = ' + value)} let kvp: KeyValueProcessor = addKeyValue;kvp(1, 'Bill'); //Output: addKeyValue: key = 1, value = Bill kvp = updateKeyValue;kvp(2, 'Steve'); //Output: updateKeyValue: key = 2, value = Steve 

Yllä olevassa esimerkissä rajapinta KeyValueProcessor sisältää metodin allekirjoituksen. Tämä määrittelee funktion tyypin. Nyt voimme määritellä muuttujan, jonka tyyppi on KeyValueProcessor ja joka voi osoittaa vain funktioihin, joiden allekirjoitus on sama kuin rajapinnassa KeyValueProcessor määritelty. Eli addKeyValue– tai updateKeyValue-funktio osoitetaan kvp:lle. Joten kvp voidaan kutsua kuin funktiota.

Yritetään osoittaa funktio, jolla on eri allekirjoitus, aiheuttaa virheen.

function delete(key:number):void { console.log('Key deleted.')} let kvp: KeyValueProcessor = delete; //Compiler Error

ADVERTISAATIO

Interfacen käyttöliittymä array-tyypille

Interfacen avulla voidaan määritellä myös array-tyyppi, jossa voidaan määritellä indeksin tyyppi sekä arvot.

Esim: Tyyppi Array

Copy

interface NumList { :number}let numArr: NumList = ;numArr;numArr;interface IStringList { :string}let strArr : IStringList;strArr = "TypeScript";strArr = "JavaScript";

Yllä olevassa esimerkissä rajapinta NumList määrittelee tyypin array, jonka indeksi on numero ja arvo on numerotyyppi. Samalla tavalla IStringList määrittelee merkkijonomäärän, jonka indeksi on merkkijono ja arvo merkkijono.

Optional Property

Joskus saatamme ilmoittaa rajapinnan, jolla on liikaa ominaisuuksia, mutta emme välttämättä odota kaikkien objektien määrittelevän kaikkia annettuja rajapinnan ominaisuuksia. Meillä voi olla valinnaisia ominaisuuksia, jotka on merkitty ”?”-merkillä. Tällaisissa tapauksissa rajapinnan objektit voivat määritellä tai olla määrittelemättä näitä ominaisuuksia.

Esimerkki: Valinnainen ominaisuus

Kopioi

interface IEmployee { empCode: number; empName: string; empDept?:string;}let empObj1:IEmployee = { // OK empCode:1, empName:"Steve"}let empObj2:IEmployee = { // OK empCode:1, empName:"Bill", empDept:"IT"}

Yllä olevassa esimerkissä empDept on merkitty ?:lla, joten IEmployee:n objektit voivat sisältää tai olla sisällyttämättä tätä ominaisuutta.

Ominaisuudet, jotka on tarkoitettu vain luettaviksi

TypeScript tarjoaa tavan merkitä ominaisuus vain luettavaksi. Tämä tarkoittaa, että kun ominaisuudelle on annettu arvo, sitä ei voi muuttaa!

Esimerkki: Readonly Property

Copy

interface Citizen { name: string; readonly SSN: number;}let personObj: Citizen = { SSN: 110555444, name: 'James Bond' }personObj.name = 'Steve Smith'; // OKpersonObj.SSN = '333666888'; // Compiler Error

Yllä olevassa esimerkissä SSN-ominaisuus on read only. Määrittelemme personObj-olion tyypin Citizen ja annamme kahdelle rajapintaominaisuudelle arvot. Seuraavaksi yritämme muuttaa molemmille ominaisuuksille – name ja SSN – annettuja arvoja. TypeScript-kääntäjä näyttää virheen, kun yritämme muuttaa vain lukuarvoa sisältävää SSN-ominaisuutta.

Rajapintojen laajentaminen

Rajapinnat voivat laajentaa yhtä tai useampaa rajapintaa. Tämä tekee rajapintojen kirjoittamisesta joustavaa ja uudelleenkäytettävää.

Esimerkki: Extend Interface

Copy

interface IPerson { name: string; gender: string;}interface IEmployee extends IPerson { empCode: number;}let empObj:IEmployee = { empCode:1, name:"Bill", gender:"Male"}

Yllä olevassa esimerkissä IEmployee-rajapinta laajentaa IPerson-rajapintaa. Niinpä IEmployee:n objektien on sisällettävä kaikki IPerson-rajapinnan ominaisuudet ja metodit, muuten kääntäjä näyttää virheen.

Rajapinnan toteuttaminen

Samankaltaisesti kuin Javan ja C#:n kaltaisissa kielissä, TypeScriptissä rajapinnat voidaan toteuttaa luokan avulla. Rajapinnan toteuttavan luokan on noudatettava tiukasti rajapinnan rakennetta.

Esimerkki: Rajapinnan toteutus

Kopioi

interface IEmployee { empCode: number; name: string; getSalary:(number)=>number;}class Employee implements IEmployee { empCode: number; name: string; constructor(code: number, name: string) { this.empCode = code; this.name = name; } getSalary(empCode:number):number { return 20000; }}let emp = new Employee(1, "Steve");

Yllä olevassa esimerkissä IEmployee rajapinta on toteutettu Employee-luokassa implement-avainsanalla. Toteuttavan luokan tulee ehdottomasti määritellä ominaisuudet ja funktio samalla nimellä ja tietotyypillä. Jos toteuttava luokka ei noudata rakennetta, kääntäjä näyttää virheen.

Tietysti toteuttava luokka voi määritellä ylimääräisiä ominaisuuksia ja metodeja, mutta ainakin sen on määriteltävä kaikki rajapinnan jäsenet.

Seuraavassa luvussa opimme lisää TypeScript-luokista.

Vastaa

Sähköpostiosoitettasi ei julkaista.