Interface är en struktur som definierar kontraktet i ditt program. Det definierar syntaxen för klasser att följa. Klasser som är härledda från ett gränssnitt måste följa den struktur som tillhandahålls av deras gränssnitt.
TypeScript-kompilatorn konverterar inte gränssnitt till JavaScript. Den använder gränssnittet för typkontroll. Detta kallas även ”duck typing” eller ”structural subtyping”.
Ett gränssnitt definieras med nyckelordet interface
och kan innehålla egenskaper och metoddeklarationer med hjälp av en funktion eller en pilfunktion.
Kopiera
interface IEmployee { empCode: number; empName: string; getSalary: (number) => number; // arrow function getManagerName(number): string; }
I exemplet ovan innehåller gränssnittet IEmployee
två egenskaper empCode
och empName
. Det innehåller också en metoddeklaration getSalaray
som använder en pilfunktion som innehåller en sifferparameter och en sifferreturtyp. Metoden getManagerName
deklareras med en normal funktion. Detta innebär att varje objekt av typen IEmployee
måste definiera de två egenskaperna och de två metoderna.
Interface som typ
Interface i TypeScript kan användas för att definiera en typ och även för att implementera den i klassen.
Följande interface IEmployee
definierar en typ av en variabel.
Kopiera
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:
I exemplet ovan innehåller ett gränssnitt KeyPair
två egenskaper key
och value
. En variabel kv1
deklareras som KeyPair
typ. Den måste alltså följa samma struktur som KeyPair
. Det innebär att endast ett objekt med egenskaperna key
av taltyp och value
av strängtyp kan tilldelas en variabel kv1
. TypeScript-kompilatorn visar ett fel om namnet på egenskaperna ändras eller om datatypen skiljer sig från KeyPair
. En annan variabel kv2
är också deklarerad som KeyPair
typ men det tilldelade värdet är val
istället för value
, så detta kommer att orsaka ett fel. På samma sätt tilldelar kv3 ett nummer till egenskapen value
, så kompilatorn kommer att visa ett fel. TypeScript använder alltså ett gränssnitt för att säkerställa att ett objekt har rätt struktur.
Interface som funktionstyp
TypeScript-gränssnitt används också för att definiera en funktionstyp. Detta säkerställer funktionssignaturen.
Kopiera
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
I ovanstående exempel innehåller ett gränssnitt KeyValueProcessor
en metodsignatur. Denna definierar funktionstypen. Nu kan vi definiera en variabel av typen KeyValueProcessor
som endast kan peka på funktioner med samma signatur som definieras i gränssnittet KeyValueProcessor
. Så addKeyValue
eller updateKeyValue
funktion tilldelas kvp
. Så kvp
kan anropas som en funktion.
Vetar du att tilldela en funktion med en annan signatur uppstår ett fel.
function delete(key:number):void { console.log('Key deleted.')} let kvp: KeyValueProcessor = delete; //Compiler Error
Interface för array-typ
Ett gränssnitt kan också definiera typen av en array där du kan definiera typen av index såväl som värden.
NumList
en typ av array med index som nummer och värde som nummertyp. På samma sätt definierar IStringList
en strängarray med index som sträng och värde som sträng.
Optionell egenskap
Ibland kan vi deklarera ett gränssnitt med överflödiga egenskaper men kanske inte förväntar oss att alla objekt ska definiera alla givna gränssnittsegenskaper. Vi kan ha valfria egenskaper, markerade med ett ”?”. I sådana fall kan objekt i gränssnittet definiera dessa egenskaper eller inte.
empDept
markerad med ?
, så objekt av IEmployee
kan inkludera den här egenskapen eller inte.
Enbart läsbara egenskaper
TypeScript erbjuder ett sätt att markera en egenskap som endast läsbar. Detta innebär att när en egenskap har tilldelats ett värde kan den inte ändras!
Kopiera
interface Citizen { name: string; readonly SSN: number;}let personObj: Citizen = { SSN: 110555444, name: 'James Bond' }personObj.name = 'Steve Smith'; // OKpersonObj.SSN = '333666888'; // Compiler Error
I exemplet ovan är egenskapen SSN
skrivskyddad. Vi definierar objektet personObj av typen Citizen och tilldelar värden till de två gränssnittsegenskaperna. Därefter försöker vi ändra de värden som tilldelats de båda egenskaperna name
och SSN
. TypeScript-kompilatorn visar ett fel när vi försöker ändra den skrivskyddade egenskapen SSN
.
Utvidgning av gränssnitt
Gränssnitt kan utvidga ett eller flera gränssnitt. Detta gör det flexibelt och återanvändbart att skriva gränssnitt.
Kopiera
interface IPerson { name: string; gender: string;}interface IEmployee extends IPerson { empCode: number;}let empObj:IEmployee = { empCode:1, name:"Bill", gender:"Male"}
I ovanstående exempel utökar gränssnittet IEmployee
gränssnittet IPerson
gränssnittet IPerson
. Så objekt av IEmployee
måste innehålla alla egenskaper och metoder i IPerson
-gränssnittet, annars visar kompilatorn ett fel.
Implementering av ett gränssnitt
I likhet med språk som Java och C# kan gränssnitt i TypeScript implementeras med en Class. Klassen som implementerar gränssnittet måste strikt följa gränssnittets struktur.
IEmployee
i klassen Employee med hjälp av nyckelordet implement. Den implementerande klassen bör strikt definiera egenskaperna och funktionen med samma namn och datatyp. Om den implementerande klassen inte följer strukturen kommer kompilatorn att visa ett fel.
Självklart kan den implementerande klassen definiera extra egenskaper och metoder, men den måste åtminstone definiera alla medlemmar i ett gränssnitt.
I nästa kapitel kommer vi att lära oss mer om TypeScript-klasser.