Цель:

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

Требования к читателю:

  • Базовый JavaScript
  • Знания TypeScript практически не требуются.
  • Просто знайте, что TypeScript - это надмножество JavaScript (это означает, что TypeScript является допустимым JavaScript, но с дополнительными методами и функциями).

Вступление

Ах да, вы встречали интерфейс на TypeScript. Может быть, вы используете Angular или React, или, может быть, вы хотите немного пообщаться с крутыми разработчиками (???). Какой бы ни была причина, интерфейсы, вероятно, появятся, и вы удивитесь трем вещам:

  • Что такое интерфейсы?
  • Когда я их использую?
  • Как мне их использовать?

Что такое интерфейсы?

Согласно официальной документации TypeScript, проверка типов «фокусируется на форме значений». Это действительно поразило меня. Всякий раз, когда я вспоминаю что-нибудь о TypeScript, в первую очередь мне приходит на ум форма. Имейте в виду, что весь смысл TypeScript в том, чтобы иметь структуру и организацию в коде вашего приложения. Интерфейсы помогают в этом. При установке типа для функций, классов или параметров интерфейс является полезным способом его определения.

Параметр с интерфейсом

Обычно интерфейсы используются в параметрах. Много раз вам придется передавать параметр, который согласуется с несколькими функциями. Вы можете возразить, что это можно сделать с классом, но давайте отложим это на потом. На данный момент помните, что интерфейсы предназначены для обеспечения «контракта».

В этом примере мы создаем приложение, которое готовит заказы на рамен для ресторана. Блюда рамэн бывают разных видов, поэтому нам понадобится структурированный, многоразовый способ подготовки этих заказов.

Давайте обеспечим выполнение приказов, которые шеф-повар может получить на своей кухне.

Простой интерфейс

Во-первых, нам нужна функция, которая создает заказ рамена для шеф-повара.

Но ждать! Каждый заказ рамена всегда будет иметь несколько свойств. Давайте просто передадим набор свойств как объект. Кроме того, по крайней мере два из этих свойств будут обязательными («лапша» и «суп»). В этом случае мы можем реализовать интерфейс, который применяет параметры до того, как повар получит заказ.

Теперь, когда мы вызываем функцию makeRamen (), мы должны убедиться, что переданный объект содержит свойства, требуемые интерфейсом RamenRecipe: лапша и суп. Любой объект, который передается в makeRamen (), должен содержать как минимум «лапшу» и «суп». Обратите внимание, что здесь также определены типы свойств (значение «лапша» в виде строки и значение «суп» в виде строки).

В этом примере заказывается блюдо basicRamen {}. Повар с радостью примет этот заказ, потому что объект, переданный в параметр, соответствует требованиям интерфейса:

  1. Объект содержит обязательные свойства.
  2. Свойства имеют тип принудительно.

Примечание. TypeScript обеспечивает проверку типов только во время компиляции. По этой причине вы можете не увидеть никаких ошибок проверки типов во время выполнения. Вы увидите это в редакторе или во время компиляции. Мы повторим этот момент в следующих разделах.

Здесь у вас есть параметр функции, реализующий простой интерфейс. Но как насчет чего-то помимо простого рамена с дополнительными ингредиентами?

Дополнительные параметры

Чтобы оставить место для необязательных свойств, мы можем просто обозначить свойства интерфейса знаком «?» синтаксис.

Не каждый заказ рамена будет содержать мясо, овощи или острые блюда. Эти свойства будут отличаться у разных клиентов. Таким образом, этот интерфейс не только учитывает потенциальные предпочтения в каждом порядке, но также оставляет место для различных значений, которые будут переданы в makeRamen (). Это помогает повару, ограничивая возможность ошибок из-за неправильного типа заказа (например, рецепта жареного риса).

Вот и вся картина.

Ограничивающие свойства

Но что, если другой разработчик, не знакомый с нашим кодом рамэна, прыгнет в его середину. Ему нужно оформить заказы для другого шеф-повара, который специализируется на заказах жареного риса. Ему нравится простота makeRamen (), и он решает вызвать ту же самую функцию.

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

Этот разработчик (с честными намерениями) попытался повторно использовать makeRamen (), что прекрасно, но применил его в неправильной ситуации. Опять же, все работает нормально. Фактически, мы могли позволить этому скользить и оставить, особенно если makeRamen () будет таким простым. Но с точки зрения удобочитаемости это было бы неудобно и запутанно (приготовьте рамэн ... но приготовьте жареный рис). Представьте, что это приложение корпоративного масштаба, и вам нужно продолжить с того места, где остановился предыдущий разработчик. Подобные предупреждения могут оказаться полезными.

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

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

Еще одна замечательная особенность интерфейсов - возможность устанавливать типы только для чтения. Как необязательный "?" синтаксис, мы просто применяем «только для чтения» к свойствам интерфейса.

Свойства «лапша» и «суп» можно задать для новой переменной.

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

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

Это отличается от ключевого слова const. Официальная документация говорит об этом лучше всего:

Самый простой способ запомнить, использовать ли только readonly или const, - это спросить, используете ли вы его для переменной или свойства. Переменные используют const, тогда как свойства используют readonly.

На этом этапе, если вам интересно, чем интерфейсы отличаются от классов, то сравнение будет правильным. Они не совпадают, но это обычное решение, которое принимают при создании повторно используемого кода. Мы вернемся к этому позже, а пока просто знайте, что интерфейсы не существуют в окончательном преобразованном пакете JavaScript.

Когда дело доходит до TypeScript, это относительно короткое время. Если вы действительно хотите выйти за рамки моих потрясающих аналогий с едой, вы можете ознакомиться с Angular Development with TypeScript Якова Файна и Антона Моисеева. Я имел удовольствие присутствовать на нескольких выступлениях Якова. Он действительно знает свой TypeScript. Лично он был из верхней части моего ценового диапазона, но это потому, что это более 500 страниц глубоких знаний. Я выбрал много частей не по порядку. На самом деле, есть части, которые я так и не закончил, но к которым всегда могу вернуться.

Что касается информации, касающейся Angular, очень примечательным упоминанием является Angular 5: от теории к практике Асима Хусейна. Это было одно из первых моих чтений по Angular. Независимо от того, используете ли вы Angular 5, 6 или 7 или даже Angular 2 или 4, эта книга охватывает базовые концепции Angular. Синтаксис и зависимости, возможно, с тех пор обновились, но я все равно возвращаюсь к этой книге всякий раз, когда мне нужно освежить в памяти основные концепции Angular. Этого определенно достаточно, чтобы начать работу или подготовить к более сложным концепциям.

На этом завершается Часть I: Параметры с интерфейсами. Это серия, состоящая из нескольких частей. Итак, мы продолжим рассмотрение интерфейсов в «Части II: Функции». Я отправлю его, как только он будет для вас готов.