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

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

Так почему же Машинопись?

Typescript - это надмножество Javascript, которое преобразуется в Javascript. Он реализует статическую типизацию, что по сути означает, что код проверяется на наличие определенных ошибок перед выполнением. Статическая типизация дает еще несколько преимуществ, чем простая проверка ошибок до того, как они приведут к сбою вашего приложения. Вывод типа означает, что среда IDE знает, чего ожидать, и может предложить варианты прогнозирования. Другими словами, больше инженеров могут работать над сервисом и фиксировать код с большей уверенностью и с меньшей когнитивной нагрузкой, связанной с необходимостью знать тонкости типов значений.

Generics идет дальше и позволяет типам, интерфейсам и классам действовать как параметры. Это позволяет нам повторно использовать код для различных случаев использования, когда входной параметр варьируется, но реализация может быть повторно использована. Так как же выглядят дженерики? Обычное соглашение - использовать T, который обозначает неизвестную переменную. Краткий пример - type Example<T> = T | T[], где <T> определяет универсальный тип, а T | T[] обозначает форму, в которой может быть передан общий тип.

Итак, когда мы будем использовать это?

Ниже описан пример, в котором мы написали код, который может выиграть от использования дженериков. В этом примере мы реализуем новый CacheService, который будет использоваться как UserService, так и UniversityService для кеширования объектов User и University соответственно.

Когда мы впервые создали наш CacheService, он был сделан как простой сервис, который взаимодействует со сторонним кешем.

Эта служба работает нормально, но мы использовали тип any дважды. Тип Typecript любого типа можно присвоить буквально любой переменной, и это не обеспечивает нам большой безопасности в отношении того, что сохраняется в нашем кеше. Первоначальная реализация CacheService в UserService и UniversityService описана ниже.

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

Что, если бы мы создали две отдельные службы кеширования?

Альтернативной реализацией было бы указать, что в кэш может передаваться только тип User или University. Для этого мы могли бы создать UserCacheService и UniversityCacheService.

Хотя мы улучшили безопасность того, что мы сохраняем в кеше, мы продублировали объем кода, который мы пишем. Одним из преимуществ универсальных шаблонов Typescript является то, что они позволяют нам сократить этот шаблонный код.

Итак, давайте реализуем несколько универсальных шаблонов.

Мы определяем службу как общий тип T, добавляя <T> после имени класса. Обратите внимание, что тип возвращаемого значения метода get и данные, которые мы сохраняем в кеше, также относятся к типу T.

Мы указываем неизвестную переменную, когда вставляем CacheService в конструкторы UserService и UniversityService. Вы можете видеть, что данные в методе set теперь указаны, как и возвращаемое значение из метода get.

Это гарантирует, что когда мы реализуем методы службы кеширования, мы должны указать правильный тип, если бы мы должны были заполнить метод set в UserService объектом, который не соответствует типу User, тогда мы увидим ошибку времени компиляции ( одно из больших преимуществ Typescript над Javascript).

Теперь мы успешно сократили объем кода, который нам нужно написать, указав, что можно сохранить в кеше, с помощью универсальных типов Typescript.

Можем ли мы еще больше повысить безопасность типов с помощью дженериков?

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

Теперь любая служба, реализующая CacheService, должна реализовывать тип, соответствующий CacheObject. ВUserService ниже мы реализовали новый UserCacheObject вместо ранее использовавшегося объекта User.

UserCacheObject реализует CacheObject, который обеспечивает наличие правильных полей.

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

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

Вот и все!

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