Typescript interface implements interface

Typescript interface implements interface

Интерфейс определяет свойства и методы, которые объект должен реализовать. Другими словами, интерфейс — это определение кастомного типа данных, но без реализации. В данном случае интерфейсы в TS похожи на интерфейсы в языках Java и C#. Интерфейсы определяются с помощью ключевого слова interface . Для начала определим простенький интерфейс:

Интерфейс в фигурных скобках определяет два свойства: id, которое имеет тип number, и name, которая представляет строку. Теперь используем его в программе:

let employee: IUser = < id: 1, name: "Tom" >console.log("id: ", employee.id); console.log("name: ", employee.name);

По сути employee — обычный объект за тем исключением, что он имеет тип IUser . Если правильнее говорить, то employee реализует интерфейс IUser. Причем эта реализация накладывает на employee некоторые ограничения. Так, employee должен реализовать все свойства и методы интерфейса IUser, поэтому при определении employee данный объект обязательно должен включать в себя свойства id и name.

Параметры методов и функций также могут представлять интерфейсы:

interface IUser < id: number; name: string; >let employee: IUser = < id: 1, name: "Alice" >function printUser(user: IUser): void < console.log("id: ", user.id); console.log("name: ", user.name) >printUser(employee);

В этом случае аргумент, который передается в функцию, должен представлять объект или класс, который реализует соответствующий интерфейс.

Читайте также:  Глобальные стили

И также можно возвращать объекты интерфейса:

interface IUser < id: number; name: string; >function buildUser(userId: number, userName: string): IUser < return < id: userId, name: userName >; > let newUser = buildUser(2, "Bill"); console.log("id: ", newUser.id); console.log("name: ", newUser.name);

Необязательные свойства и свойства только для чтения

При определении интерфейса мы можем задать некоторые свойства как необязательные с помощью знака вопроса. Подобные свойства реализовать необязательно:

interface IUser < id: number; name: string; age?: number; >let employee: IUser = < id: 1, name: "Alice", age: 23 >let manager: IUser =

Свойство age помечено как необязательное, поэтому его можно не определять в объектах.

Также интерфейс может содержать свойства только для чтения, значение которых нельзя изменять. Такие свойства определяются с помощью ключевого слова readonly :

interface Point < readonly x: number; readonly y: number; >let p: Point = < x: 10, y: 20 >; console.log(p); // p.x = 5; // Ошибка - свойство доступно только для чтения

Определение методов

Кроме свойств интерфейсы могут определять функции:

interface IUser < id: number; name: string; sayWords(words: string): void; >let employee: IUser = < id: 1, name: "Alice", sayWords: function(words: string): void< console.log(`$говорит "$"`); > > employee.sayWords("Привет, как дела?");

Опять же объект, который реализует интерфейс, также обязан реализовать определенную в интерфейсе функцию с тем же набором параметров и тем типом выходного результата. В данном случае функция sayWords() в качестве параметра принимает строку и ничего возвращает, выводя на консоль некоторое сообщение.

Интерфейсы классов

Интерфейсы могут быть реализованы не только объектами, но и классами. Для этого используется ключевое слово implements :

interface IUser < id: number; name: string; getFullName(surname: string): string; >class User implements IUser < id: number; name: string; age: number; constructor(userId: number, userName: string, userAge: number) < this.id = userId; this.name = userName; this.age = userAge; >getFullName(surname: string): string < return this.name + " " + surname; >> let tom = new User(1, "Tom", 23); console.log(tom.getFullName("Simpson"));

Класс User реализует интерфейс IUser. В этом случае класс User обязан определить все те же свойства и функции, которые есть в IUser.

При этом объект tom является как объектом User, так и объектом IUser:

let tom :IUser = new User(1, "Tom", 23); //или let tom :User = new User(1, "Tom", 23);

Расширение интерфейса

TypeScript позволяет добавлять в интерфейс новые поля и методы, просто объявив интерфейс с тем же именем и определив в нем необходимые поля и методы. Например:

interface IUser < id: number; name: string; >interface IUser < age: number; >let employee: IUser = < id: 1, name: "Alice", age: 31 >function printUser(user: IUser): void < console.log(`id: $name: $ age: $`); > printUser(employee);

В данном случае первое определение интерфейса IUser содержит поля id и name . Второе определение интерфейса содержит объявление поля age . В итоге объект или класс, который реализует этот интерфейс, должен определить все три поля — id, name и age.

Наследование интерфейсов

Интерфейсы, как и классы, могут наследоваться:

interface IMovable < speed: number; move(): void; >interface ICar extends IMovable < fill(): void; >class Car implements ICar < speed: number; move(): void < console.log("Машина едет со скоростью " + this.speed + " км/ч"); >fill(): void < console.log("Заправляем машину топливом"); >> let auto = new Car(); auto.speed = 60; auto.fill(); auto.move();

После наследования интерфейс ICar будет также иметь все те свойства и функции, которые определены в IMovable. И тогда, класс Car, реализующий интерфейс ICar, должен будет реализовать также и свойства и методы интерфейса IMovable.

Интерфейсы функций

Интерфейсы функций содержат определение типа функции. Затем они должны быть реализованы объектом, который представляет функцию данного типа:

interface FullNameBuilder < (name: string, surname: string): string; >let simpleBuilder: FullNameBuilder = function (name:string, surname: string): string < return "Mr. " + name + " " + surname; >let fullName = simpleBuilder("Bob", "Simpson"); console.log(fullName); // Mr. Bob Simpson

Здесь определен интерфейс FullNameBuilder, который лишь содержит сигнатуру функции. Далее определяется переменная simpleBuilder, которая имеет тип FullNameBuilder и поэтому должна представлять функцию с данной сигнатурой.

Интерфейсы массивов

Интерфейсы массивов описывают объекты, к которым можно обращаться по индексу, как, например, к массивам

interface StringArray < [index: number]: string; >let phones: StringArray; phones = ["iPhone 7", "HTC 10", "HP Elite x3"]; let myPhone: string = phones[0]; console.log(myPhone);

Здесь определен интерфейс StringArray, который содержит сигнатуру массива. Эта сигнатура указывает, что объект, который реализует StringArray, может индексироваться с помощью чисел (объекта типа number). И, кроме того, данный объект должен хранить объекты типа string , то есть строки.

Выше индекс представлял тип number. Но мы можем использовать для индексации и тип string:

interface Dictionary < [index: string]: string; >var colors: Dictionary = <>; colors["red"] = "#ff0000"; colors["green"] = "#00ff00"; colors["blue"] = "#0000ff"; console.log(colors["red"]);

Гибридные интерфейсы

Интерфейсы могут сочетать различные стили, могут применяться сразу как к определению объекта, так и к определению функции:

interface PersonInfo < (name: string, surname: string):void; fullName: string; password: string; authenticate(): void; >function personBuilder(): PersonInfo < let person = function (name: string, surname: string): void< person.fullName = name + " " + surname; >; person.authenticate = function () < console.log(person.fullName + " входит в систему с паролем " + person.password); >; return person; > let tom = personBuilder(); tom("Tom", "Simpson"); tom.password = "qwerty"; tom.authenticate();

Тип функции, определяемый в таком гибридном интерфейсе, как правило, выступает в роли конструктора объекта. В данном случае такой конструктор имеет тип (name: string, surname: string):void; .

А функция, которая представляет данный интерфейс (в данном случае — функция personBuilder ), реализует эту функцию конструктора, и также может использовать другие свойства и методы, которые были определены в интерфейсе.

Источник

How Does An Interface Work In TypeScript?

Tim Mouskhelichvili

TypeScript, just like many modern object-oriented languages, allows a developer to create an interface. But what is it, and how to use it?

An interface is a contract structure that defines the syntax that a class or object must follow.

This article explains how interfaces work and shows different use cases with complete code examples.

typescript interface

The definition

An interface is a structure that defines the contract that an object or class must follow.

Using an interface, a developer can define the methods and properties that an object or class must implement.

To define an interface in TypeScript, you must use the interface keyword.

TypeScript does not convert interfaces to JavaScript. The TypeScript compiler uses them for type checking. If you do not define the return interface of a function, the compiler can implicitly infer it.

Here is an example of an interface:

typescriptinterface IPerson < name: string; age: number; > const person: IPerson = < age: 27, name: 'Tim' >;

This interface defines a shape with two required properties. To be valid, the person constant must follow the exact structure (same properties with the same data types) of the IPerson interface. You must follow the interface structure to avoid getting a TypeScript error.

To type-check an interface, you can define a type guard.

Also, TypeScript provides various utility types to help developers work with interfaces.

Defining an optional property

TypeScript provides support for optional properties inside interfaces. A developer must place a question mark after the property’s name to define one. Here is an example:

typescriptinterface IPerson < name: string; age?: number; > const person: IPerson = < name: 'Tim' >; const person2: IPerson = < name: 'Bob', age: 28 >;

Defining a read-only property

Also, a developer can define a read-only property inside an interface by using the readonly keyword. Here is an example:

typescriptinterface IPerson < readonly name: string; > const person: IPerson = < name: 'Tim' >; // This doesn't work because the property is read-only. person.name = 'Bob';

Indexable Types

Using an interface, you can also define an indexable signature. Indexable signatures are helpful when you know the data types of the keys and values of an object, but its structure is unknown. When defining the data type of the key of an indexable signature, you can only use a string , a number , a symbol , a template string pattern, or a union of those. Here is an example:

typescriptinterface IndexSignature < Typescript interface implements interface: string; > const index: IndexSignature = < prop1: 'value1', prop2: 'value2', >;

In this example, we can add any string key/value pair to the index constant. Note: If you want mapped properties, you must use a type instead of an interface. Note: You can also use the Record utility type to achieve a similar result. Read more: 4 ways to create a map in TypeScript.

Generic interfaces

TypeScript interfaces also allow the use of generic parameters. A generic parameter is helpful when you do not know the data type of a property. In short, generics help create reusable components AND provide generic type-checking. Here is an example:

typescriptinterface IPerson < name: string; data: T; > const p1: IPersonstring> = < data: 'blablabla', name: 'Tim' > const p2: IPersonnumber> = < data: 20, name: 'Tim' >

In this example, we create two constants that implement the IPerson interface. For the first constant, p1 , we pass a string as the generic argument. That’s why data can only be a string . For the second constant, p2 , we pass a number as the generic argument. That’s why data can only be a number .

How to extend an interface?

If you want to add a property or method to an interface, you can extend the interface using the extends keyword. Here is an example:

typescriptinterface IAnimal < name: string; > interface IDog extends IAnimal < bark: () => void; breed: string; >

In this example, we extend the IDog interface with all the properties from the IAnimal interface. Note: You can extend multiple interfaces by passing them as a comma-separated list. Read more: How to extend an interface?

How to implement an interface?

A TypeScript class can implement one or multiple interfaces using the implements keyword. Here is an example:

typescriptinterface IAnimal < name: string; eat: () => void; > class Fish implements IAnimal < public constructor( public name: string ) < >public eat () < console.log('The fish is eating.'); > > const fish = new Fish('Fishy'); // "The fish is eating." fish.eat();

In this example, the Fish class implements the IAnimal interface. If one or more properties/methods from the interface are missing inside the class that implements it, the TypeScript compiler will output an error. Read more: How to make a class implement an interface?

Difference between an interface VS a type

  • An interface cannot declare a primitive.
  • An interface cannot contain mapped properties.
  • A type cannot participate in declaration merging.

To learn more, read this article: Differences between a type VS an interface.

Difference between an interface VS a class

An interface and a class are two completely different concepts.

In TypeScript, a class is an object that exists at runtime and encapsulates related properties and methods.

On the other hand, an interface is a structure that doesn’t exist at runtime, only used for type-checking a class or object.

Final thoughts

As you can see, defining an interface is easy in TypeScript.

Regarding its naming convention, some developers prefix all interface names with the capital letter I, and some don’t. TypeScript’s original developers advise not to prefix since the concept of a Typescript interface is much broader than in languages such as C#.

As for me, I prefer to prefix, to differentiate between types and interfaces.

typescript interface

Here are some other TypeScript tutorials for you to enjoy:

The best Web Development course in 2023! 👉 Learn Web Development

Tim Mouskhelichvili

Hello! I am Tim Mouskhelichvili, a Freelance Developer & Consultant from Montreal, Canada. I specialize in React, Node.js & TypeScript application development. If you need help on a project, please reach out, and let’s work together.

Источник

Оцените статью