Развлечения с марками. Эпизод 16. Смешанные классы TypeScript против штампов
Привет. Я разработчик Василий Боровяк, и добро пожаловать в шестнадцатый выпуск Василия Боровяка, представляющего Fun with Stamps.
TL;DR
Внизу вы найдете мой фантазийный синтаксис штампов, если бы он был частью TypeScript.
Что такое смешанные классы TypeScript?
Недавно TypeScript v2.2 выпустил новую классную функцию - смешивание классов. По сути, теперь вы можете «смешивать классы». Именно для этого и предназначено марки - «смешивание марок».
TypeScript - отличный язык. Это дает вам жесткий контроль над вашими типами объектов, что часто является полезной функцией.
В этом выпуске единственное, что я хотел бы отметить, это то, что функцию «смешивания классов» трудно читать. Конечно, это зависит от ваших навыков TypeScript. Но давайте представим, что вы посредственный ленивый разработчик, впервые читающий код.
Вот официальный пример из Примечаний к выпуску TypeScript v2.2.
Сколько времени нужно, чтобы понять, что здесь происходит?
Давайте перепишем его штампами.
Сколько времени вам, моему воображаемому посредственному разработчику, нужно, чтобы разобраться в приведенном ниже коде?
import stampit from '@stamp/it'; const Point = stampit({ init ({x, y}) { this.x = x; this.y = y; } }); const Person = stampit({ init ({name}) { this.name = name; } }); const Tagged = stampit({ init ({_tag}) { this._tag = _tag; } }); const TaggedPoint = stampit(Point, Tagged); let point = TaggedPoint({x: 10, y: 20, _tag: 'hello'}); const Customer = stampit(Person, Tagged, { init ({accountBalance = 0}) { this.accountBalance = accountBalance; } }); let customer = Customer({accountBalance: 0, _tag: 'test'});
В штампах вы можете предоставить все аргументы инициализатору (он же конструктор). В TypeScript вам нужно назначить свойства после, что вы создали объект.
Но самое главное, что более читаемо вам?
Фэнтезийный синтаксис TypeScript
TypeScript имеет множество других удивительных функций. Но я бы хотел, чтобы штампы были частью TypeScript, а не отдельным модулем.
Пример синтаксиса:
stamp Point { constructor({public x: number, public y: number}) {} } stamp Person { constructor({public name: string}) {} } stamp Tagged { constructor({public _tag: string}) {} } stamp TaggedPoint extends Point, Tagged; let point = TaggedPoint({x: 10, y: 20, _tag: 'hello'}); stamp Customer extends Person, Tagged, { constructor({public accountBalance: number = 0}) {} }; let customer = Customer({accountBalance: 0, _tag: 'test'});
Хорошее начало! Давайте еще пофантазируем. Преобразуем простые штампы из самого первого эпизода Fun with Stamps. Свойства, методы, инициализаторы:
stamp HasFoo { public foo: number = 'default foo'; } stamp PrintFoo { public printFoo() { console.log(this.foo || 'There is no foo'); } } stamp InitFoo { constructor({public foo: string}) {} } stamp Foo extends HasFoo, PrintFoo, InitFoo; // This should work, const Foo = stamp(HasFoo, PrintFoo, InitFoo); // and this too. const obj = Foo('incoming foo!'); obj.printFoo(); // incoming foo!
А как насчет статики?
stamp TraceStampMetaData { public static trace() { console.log(`This stamp consists of ${this.stamp}`); } }); stamp Foo2 extends Foo, TraceStampMetaData; // These two lines const Foo3 = stamp(Foo, TraceStampMetaData); // are identical. Foo2.trace(); // prints Foo2.stamp meta-data Foo3.trace(); // prints Foo3.stamp meta-data
Было бы замечательно, если бы разработчики могли выбирать между синтаксисом stamp()
и extends
по своему усмотрению. Точно так же, как мы можем выбирать между синтаксисом .then()
и await
в ES6.
Остальные части TypeScript должны работать со штампами так же, как они работают с классами (дженерики, интерфейсы и т. Д.).
Это очень привлекательно. Этот синтаксис убедит меня перейти на TypeScript на постоянной основе.
Различия между классами TypeScript и штампами
- Благодаря штампам синтаксис становится проще и короче.
- Со штампами у вас может быть столько конструкторов, сколько захотите. Все получат точно такие же аргументы.
- В штампах нет цепочки наследования - это основная причина того, что синтаксис намного проще. Все методы относятся к
__proto__
экземплярам ваших объектов по соображениям производительности. - Вы можете использовать множественное наследование.
- Марки не требуют ключевого слова
new
. Таким образом, при необходимости его можно заменить простой заводской функцией. - С марками у вас есть прямой доступ к метаданным вашей марки. Посмотреть здесь". Имея эту информацию, вы можете создавать более умные вещи.
instanceof
не работает со штампами по дизайну. (Если это действительно необходимо, я бы порекомендовал реализовать ключевое слово TypeScriptobj is Foo
какobj.__proto__ === Foo.stamp.methods
. Но лучше вообще не использовать его.)- … Я изо всех сил пытался найти недостатки штампованного подхода, но у меня ничего не вышло. Пожалуйста, помогите мне…
Удачи с марками!
- Эпизод 1. Основы штампа
- Эпизод 2. Внедрение зависимостей в FP
- Эпизод 3. Сравнение с классами ES2015
- Эпизод 4. Самостоятельная реализация штампов в 30 LOC
- Эпизод 5. Шаблон оформления композиции
- Эпизод 6. Статика - свойства на марках
- Эпизод 7. Ранняя и поздняя инъекция зависимости
- Эпизод 8. Отслеживание и переопределение композиции
- Эпизод 9. Отключение композиции ()
- Эпизод 10. Моя ментальная модель штампа
- Эпизод 11. Мешающий состав
- Эпизод 12. Новый дом @stamp
- Эпизод 13. Метод контроля коллизий
- Эпизод 14. Новый @ штамп / он на замену Stampit
- Эпизод 15. Экосистема @stamp / modules
- Эпизод 16. Смешанные классы TypeScript и штампы (эта статья)
- Эпизод 17. Простое 100% покрытие модульных тестов на JS
- Эпизод 18. Рай для инъекций зависимости
- Эпизод 19. Абстрактные методы Java / C # в JavaScript
- Эпизод 20. Stampit v4
- Эпизод 21. Приватные данные в JavaScript. 4 способа использования штампов
- Эпизод 22. Экземпляр JavaScript как составной штамп
- Эпизод 23. Новый stampit.js.org со всеми документами
- Эпизод 24. Новая« именная функция»