Rozhraní je struktura, která definuje smlouvu ve vaší aplikaci. Definuje syntaxi, kterou se mají třídy řídit. Třídy, které jsou odvozeny z rozhraní, musí dodržovat strukturu danou jejich rozhraním.
Překladač jazyka TypeScript nepřevádí rozhraní do jazyka JavaScript. Pro kontrolu typů používá rozhraní. Tomu se také říká „kachní typování“ nebo „strukturální podtypování“.
Rozhraní se definuje pomocí klíčového slova interface a může obsahovat deklarace vlastností a metod pomocí funkce nebo funkce se šipkou.
Kopírovat
interface IEmployee { empCode: number; empName: string; getSalary: (number) => number; // arrow function getManagerName(number): string; }
Ve výše uvedeném příkladu obsahuje rozhraní IEmployee dvě vlastnosti empCode a empName. Dále obsahuje deklaraci metody getSalaray využívající funkci arrow, která obsahuje jeden číselný parametr a číselný návratový typ. Metoda getManagerName je deklarována pomocí normální funkce. To znamená, že každý objekt typu IEmployee musí definovat tyto dvě vlastnosti a dvě metody.
Rozhraní jako typ
Rozhraní v jazyce TypeScript lze použít k definici typu a také k jeho implementaci ve třídě.
Následující rozhraní IEmployee definuje typ proměnné.
Kopie
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:
Ve výše uvedeném příkladu rozhraní KeyPair obsahuje dvě vlastnosti key a value. Proměnná kv1 je deklarována jako typ KeyPair. Musí tedy mít stejnou strukturu jako KeyPair. To znamená, že proměnné kv1 lze přiřadit pouze objekt s vlastnostmi key typu číslo a value typu řetězec. Překladač jazyka TypeScript zobrazí chybu, pokud dojde ke změně názvu vlastností nebo je datový typ jiný než KeyPair. Další proměnná kv2 je také deklarována jako typ KeyPair, ale přiřazená hodnota je val místo value, takže to způsobí chybu. Stejně tak kv3 přiřadí vlastnosti value číslo, takže překladač zobrazí chybu. TypeScript tedy používá rozhraní, které zajišťuje správnou strukturu objektu.
Rozhraní jako typ funkce
Rozhraní jazyka TypeScript se také používá k definování typu funkce. Tím se zajistí signatura funkce.
Kopie
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
Ve výše uvedeném příkladu obsahuje rozhraní KeyValueProcessor signaturu metody. Ta definuje typ funkce. Nyní můžeme definovat proměnnou typu KeyValueProcessor, která může ukazovat pouze na funkce se stejnou signaturou, jaká je definována v rozhraní KeyValueProcessor. Takže funkci addKeyValue nebo updateKeyValue přiřadíme funkci kvp. Proměnnou kvp lze tedy volat jako funkci.
Pokus o přiřazení funkce s jinou signaturou způsobí chybu.
function delete(key:number):void { console.log('Key deleted.')} let kvp: KeyValueProcessor = delete; //Compiler Error
Rozhraní pro typ pole
Rozhraní může také definovat typ pole, kde můžete definovat typ indexu i hodnoty.
Kopírovat
interface NumList { :number}let numArr: NumList = ;numArr;numArr;interface IStringList { :string}let strArr : IStringList;strArr = "TypeScript";strArr = "JavaScript";
Ve výše uvedeném příkladu definuje rozhraní NumList typ pole s indexem jako číslo a hodnotou jako typ číslo. Stejně tak rozhraní IStringList definuje pole typu string s indexem jako string a hodnotou jako string.
Volitelné vlastnosti
Někdy můžeme deklarovat rozhraní s nadbytečnými vlastnostmi, ale nemusíme očekávat, že všechny objekty budou definovat všechny dané vlastnosti rozhraní. Můžeme mít nepovinné vlastnosti, označené znakem „?“. V takových případech objekty rozhraní mohou, ale nemusí tyto vlastnosti definovat.
Kopírovat
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"}
V uvedeném příkladu je empDept označen ?, takže objekty IEmployee mohou, ale nemusí tuto vlastnost obsahovat.
Vlastnosti pouze pro čtení
TypeScript poskytuje možnost označit vlastnost pouze pro čtení. To znamená, že jakmile je vlastnosti přiřazena hodnota, nelze ji měnit!
SSN určena pouze pro čtení: Kopírovat interface Citizen { name: string; readonly SSN: number;}let personObj: Citizen = { SSN: 110555444, name: 'James Bond' }personObj.name = 'Steve Smith'; // OKpersonObj.SSN = '333666888'; // Compiler Error
V uvedeném příkladu je vlastnost SSN určena pouze pro čtení. Definujeme objekt personObj typu Citizen a přiřadíme hodnoty dvěma vlastnostem rozhraní. Dále se pokusíme změnit hodnoty přiřazené oběma vlastnostem – name a SSN. Kompilátor jazyka TypeScript zobrazí chybu, když se pokusíme změnit vlastnost SSN pouze pro čtení.
Rozšiřování rozhraní
Rozhraní mohou rozšiřovat jedno nebo více rozhraní. Díky tomu je psaní rozhraní flexibilní a opakovaně použitelné.
Kopírovat
interface IPerson { name: string; gender: string;}interface IEmployee extends IPerson { empCode: number;}let empObj:IEmployee = { empCode:1, name:"Bill", gender:"Male"}
V uvedeném příkladu rozšiřuje rozhraní IEmployee rozhraní IPerson. Objekty IEmployee tedy musí obsahovat všechny vlastnosti a metody rozhraní IPerson, jinak překladač zobrazí chybu.
Implementace rozhraní
Podobně jako v jazycích jako Java a C# lze rozhraní v jazyce TypeScript implementovat pomocí třídy. Třída implementující rozhraní musí striktně dodržovat strukturu rozhraní.
Kopírovat
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");
Ve výše uvedeném příkladu je rozhraní IEmployee implementováno ve třídě Employee pomocí klíčového slova implement. Implementační třída by měla striktně definovat vlastnosti a funkce se stejným názvem a datovým typem. Pokud implementační třída nedodrží strukturu, pak překladač zobrazí chybu.
Implementační třída samozřejmě může definovat další vlastnosti a metody, ale přinejmenším musí definovat všechny členy rozhraní.
V příští kapitole se dozvíme více o třídách jazyka TypeScript.