Ты неправильно используешь интерфейсы typescript

100d9bfff97a096c006d949bffc73621

A: Не думай о помощи.
Б: Сложно не думать о помощи, когда пишешь на javascript.

Примерно такой диалог я слышал на одной из конференции. Решить проблему отсутствия строгой типизации был призван typescript.

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

Для большинства typescript разработчиков типы и интерфейсы, не имеют как таковой большой разницы.

type Dog = {name: string, age: number}

interface Dog {
name: string,
age: number
}

И запись при помощи интерфейса и при помощи типа по своей сути равнозначно смогут дальше работать, и подсказывать ошибки типизации при дальнейшей разработке

Что я предлагаю?

Я предлагаю разделять эти 2 понятия:

  1. Типы используем когда хотим описать определенные атрибуты объектов.

  2. Интерфейсы когда хотим описать поведение объектов, их методы.

Для начала создадим интерфейс «greeter».

interface greeter {
  greet() : void;
}

Создадим типы «Dog» и «Cat».

type Dog = {name: string, age: number}
type Cat = {first_name: string, second_name: string, owner: string}

Как мы видим эти типы, имеют различные наборы атрибутов.

Далее создадим функцию, которая принимает в качестве первого аргумента, объект удовлетворяющий интерфейсу «greeter» и далее вызывает его метод «greet».

function greet(g: greeter) {
  g.greet();
}

Что-бы наши типы «Dog» и «Cat», можно было использовать при вызове функции «greet», необходимо явно объединить типы «Dog» и «Cat» c интерфейсом «greeter»

type Dog = {name: string, age: number} & greeter
type Cat = {first_name: string, second_name: string, owner: string} & greeter

Реализуем объект каждого типа

const dog: Dog = {
  name: "jack",
  age: 10,
  
  greet() {
    console.log(`hello im dog. My name is ${this.name}. I'm ${this.age} years old.`)
  }
}

const cat: Cat = {
  first_name: "Myley",
  second_name: "Meows",
  owner: "Ivan",
  
  greet() {
    console.log(`hello im cat. My name is ${this.first_name} ${this.second_name}. My owner name is ${this.owner}`);
  }
}

Что мы имеем? У нас 2 объекта, разные по своей реализации, но их объединяет наличие метода, указанного в интерфейсе «greeter»

Вызовем эти методы

greet(dog);//"hello im dog. My name is jack. I'm 10 years old."
greet(cat);//"hello im cat. My name is Myley Meows. My owner name is Ivan"

Итог:

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

Например с точки зрения реализации пользователя и администратора в рамках одного приложения, они могут иметь различный набор атрибутов. Но в конце концов для их создания, нужно использовать один и тот же хендлер бекенда.

Код становится чище и в результате более легким для восприятия.

Позволяет разделять приложения, на более мелкие, независимые слои.

© Habrahabr.ru