Изучите использование и разработку декораторов параметров и подготовьтесь к декораторам методов.
Декораторы позволяют нам добавлять дополнительную информацию к классам или методам в TypeScript и похожи на аннотации, например, в Java. Декораторы параметров применяются к определениям параметров метода в TypeScript. С их помощью мы можем записывать информацию о параметрах, включая индивидуальную информацию, используя эти данные в других функциях.
В этой статье мы рассмотрим разработку декораторов для параметров метода в TypeScript. Вот как на практике выглядят декораторы параметров:
@ClassDecorator() class A { ... @MethodDecorator() fly( @ParameterDecorator(?? optional parameters) meters: number ) { // code } ... }
Как мы увидим, мы мало что можем сделать с декораторами параметров из-за минимальной информации, получаемой функцией декоратора. Это сделает важным обмен данными между декораторами параметров и другим кодом, например декораторами методов.
Чтобы использовать декораторы, в TypeScript должны быть включены две функции, поэтому обязательно ознакомьтесь со статьей Введение в декораторы в этой серии.
Эта статья является частью серии:
- Знакомство с декораторами
- Декораторы класса
- Декораторы недвижимости
- Декораторы аксессуаров
- Декораторы параметров Эта статья
- Декораторы методов
- Гибридные декораторы
- Использование Reflection и Reflection API с декораторами
- Проверка данных во время выполнения с помощью декораторов
Изучение декораторов параметров в TypeScript
Декораторы параметров присоединяются к параметрам конструкторов классов или методов-членов класса. Их нельзя использовать с отдельной функцией, потому что вы получите сообщение об ошибке Декораторы здесь недействительны. Их можно использовать только с параметрами функций, которые являются частью определения класса, как показано выше.
Сигнатура для функций декоратора параметров:
- Либо функция-конструктор класса для статического члена, либо прототип класса для члена-экземпляра.
- Строка, задающая имя свойства
- Порядковый индекс параметра в списке параметров функции
Первые два аргумента аналогичны аргументам, предоставляемым функциям-декораторам свойств и методов доступа. Третий относится к позиции в списке параметров метода класса:
class ClassName { method(param0, param1, param2, param3, ...) { .. } }
Параметры нумеруются индексом, начинающимся с 0, как показано здесь. Третий аргумент — это просто целое число, задающее индекс, например 0
, 1
, 2
и т. д.
В других декораторах объект с именем PropertyDescriptor представлен в третьем аргументе. С этим дескриптором можно делать много интересных вещей, но он недоступен для декораторов параметров.
Простой пример декораторов параметров в TypeScript
Чтобы увидеть, как это работает, давайте попробуем простой пример, который печатает полученные значения:
import * as util from 'util'; function logParameter(target: Object, propertyKey: string | symbol, parameterIndex: number) { console.log(`logParameter ${target} ${util.inspect(target)} ${String(propertyKey)} ${parameterIndex}`); } class ParameterExample { member(@logParameter x: number, @logParameter y: number) { console.log(`member ${x} ${y}`); } } const pex = new ParameterExample(); pex.member(2, 3); pex.member(3, 5); pex.member(5, 8);
Тип для target
указан как общий Object
. propertyKey
— это имя функции, в данном случае member
. parameterIndex
— это целое число, начинающееся с 0
, перечисляющее параметр, к которому привязан этот декоратор.
Запустив этот скрипт, мы получим следующий вывод:
$ npx ts-node lib/parameters/parameters.ts logParameter [object Object] {} member 1 logParameter [object Object] {} member 0 member 2 3 member 3 5 member 5 8
target
оказывается анонимным Объектом. В противном случае значения ключа и индекса соответствуют ожидаемым.
Обратите внимание, что у декоратора параметров нет возможности выполнять код для экземпляров объекта, содержащего параметр. Вместо этого область его воздействия приходится на время создания объекта класса. В отличие от других декораторов, нам не дается какой-либо объект, который можно изменить, чтобы повлиять на поведение экземпляров класса.
Вместо этого декоратор параметра служит главным образом маркером, добавляющим информацию к параметру метода. Официальная документация ясно говорит об этом:
Декоратор параметров можно использовать только для наблюдения за тем, что параметр был объявлен в методе.
В большинстве случаев выполнение каких-либо важных действий с помощью декоратора параметров требует сотрудничества с другими декораторами. Например, декоратор параметров может хранить данные с помощью API-интерфейсов Reflection и Reflection Metadata, а другие декораторы могут использовать эти данные при реализации других функций.
Подробный анализ данных, доступных декораторам параметров
Существует потенциальная ценность глубокого осмотра объекта target
. Из документации TypeScript мы видим, что это объект класса, так что давайте проверим, что это значит.
В пакете decorator-inspectors
есть декоратор, который мы можем использовать. Этот пример получен из этого декоратора:
export function ParameterInspector(target: Object, propertyKey: string | symbol, parameterIndex: number) { const ret = { target, propertyKey, parameterIndex, ownKeys: Object.getOwnPropertyNames(target), members: {} }; for (const key of Object.getOwnPropertyNames(target)) { ret.members[key] = { obj: target[key], descriptor: util.inspect( Object.getOwnPropertyDescriptor(target, key) ) }; } console.log(ret); }
Он извлекает список имен свойств, а затем получает дополнительные сведения об этих свойствах.
Если мы заменим @ParameterInspector
на @logInspector
в приведенном выше примере, мы получим следующий вывод:
{ target: {}, propertyKey: 'member', parameterIndex: 0, ownKeys: [ 'constructor', 'member' ], members: { constructor: { obj: [class ParameterExample], descriptor: '{\n' + ' value: [class ParameterExample],\n' + ' writable: true,\n' + ' enumerable: false,\n' + ' configurable: true\n' + '}' }, member: { obj: [Function: member], descriptor: '{\n' + ' value: [Function: member],\n' + ' writable: true,\n' + ' enumerable: false,\n' + ' configurable: true\n' + '}' } } }
Действительно, из этого становится ясно, что target
— это класс, показанный выше. Список, возвращаемый getOwnPropertyNames
, представляет собой имена методов, включая constructor
в качестве метода, хотя мы явно не создавали конструктор. Доступен даже PropertyDescriptor.
Регистрация декораторов параметров в фреймворке
Мы только что обсудили, как было бы полезно где-то сохранить данные декоратора параметров, чтобы другие декораторы могли что-то делать с этими данными. Как мы уже говорили с декораторами классов и декораторами свойств, ваши декораторы могут быть частью структуры, где каждый из них работает вместе для достижения более крупной цели.
Примером может быть метод обработки маршрута в классе, представляющем маршрутизатор в веб-инфраструктуре, такой как Express. Мы можем захотеть внедрить его в значения параметров, полученные из строки запроса в URL-адресе, или параметры тела в запросе POST.
@Router('/blog') class BlogRouter { @Get('/view/:id') viewPost(req, res, next, @URLParam('id') id: string ) { // handle route } }
В библиотеке декораторов Reflet для Express есть такие декораторы параметров, как и другие декораторы, показанные здесь. Для этого примера давайте реализуем только ту часть URLParam
, которая записывает некоторые данные. Когда мы будем работать с декораторами методов, мы создадим более полный пример, где декораторы методов и параметров работают вместе.
const registered = []; function URLParam(id: string) { return (target: Object, propertyKey: string | symbol, parameterIndex: number) => { const topush = { target, propertyKey, parameterIndex, urlparam: id, ownKeys: Object.getOwnPropertyNames(target), function: target[propertyKey], // funcDescriptor: Object.getOwnPropertyDescriptor(target, propertyKey) }; registered.push(topush); } } class BlogRouter { viewPost(req, res, next, @URLParam('id') id: string ) { console.log(`viewPost`); } viewComments(req, res, next, @URLParam('id') id: string, @URLParam('commentID') commentID: string ) { console.log(`viewComments`); } } console.log(registered);
URLParam
— это функция дескриптора параметра, которая собирает некоторые данные о декораторе параметра и методе, содержащем этот параметр. Он сохраняет это в массив с намерением, чтобы другие декораторы или фреймворк использовали эти данные для создания чего-то полезного. При обсуждении API отражения и метаданных мы увидим более практичный способ хранения этого массива данных.
В классе BlogRouter
у нас есть два метода с несколькими параметрами, разделенными между ними, а некоторые параметры имеют @URLParam
декораторов.
Затем мы можем запустить скрипт следующим образом:
$ npx ts-node lib/parameters/urlparam.ts [ { target: {}, propertyKey: 'viewPost', parameterIndex: 3, urlparam: 'id', ownKeys: [ 'constructor', 'viewPost', 'viewComments' ], function: [Function: viewPost] }, { target: {}, propertyKey: 'viewComments', parameterIndex: 4, urlparam: 'commentID', ownKeys: [ 'constructor', 'viewPost', 'viewComments' ], function: [Function: viewComments] }, { target: {}, propertyKey: 'viewComments', parameterIndex: 3, urlparam: 'id', ownKeys: [ 'constructor', 'viewPost', 'viewComments' ], function: [Function: viewComments] } ]
Это дает нам три соответствующих объекта данных. Поле propertyKey
содержит имя метода, содержащего параметр, а поле parameterIndex
содержит его индекс в списке параметров. Затем мы записываем в urlparam
, какой элемент нужно получить по URL-адресу. Затем мы записываем список имен функций, а также объект функции для метода, потому что они могут быть полезны.
Мы доказали, что очень легко записывать любые данные о свойствах, которые нам нравятся, в другом месте.
Краткое содержание
Мы можем прикреплять декораторы к параметрам метода. Это означает, что мы можем записывать информацию о декораторах, прикрепленных к каждому параметру, а затем что-то делать с этими данными.
Природа данных, предоставляемых функции декоратора, ограничивает возможности функции. Это означает, что мы будем искать функцию декоратора метода, чтобы использовать данные о декораторах параметров, чтобы сделать что-то полезное.
об авторе
Дэвид Херрон: Дэвид Херрон — писатель и инженер-программист, занимающийся вопросами разумного использования технологий. Его особенно интересуют экологически чистые энергетические технологии, такие как солнечная энергия, энергия ветра и электромобили. Дэвид почти 30 лет работал в Силиконовой долине над программным обеспечением, начиная от систем электронной почты и заканчивая потоковым видео и языком программирования Java, и опубликовал несколько книг о программировании Node.js и электромобилях.
Первоначально опубликовано на https://techsparx.com.
Дополнительные материалы на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Получите эксклюзивный доступ к возможностям написания и советам в нашем сообществе Discord.