PurpleSchool — курсы программирования онлайн
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Новые декораторы в TypeScript 5.0

    Новые декораторы в TypeScript 5.0

    Аватар автора Новые декораторы в TypeScript 5.0

    Антон Ларичев

    Иконка календаря17 марта 2023

    Введение

    Сегодня мы более детально поговорим о декораторах в TypeScript 5.0 и рассмотрим примеры их использования.

    Подготовка проекта

    Разберем настройку проекта, которая необходима для работы с декораторами:

    • Выполним инициализацию файла package.json с помощью команды npm init.
    • Используем команду tsc --init для инициализации файла tsconfig.json.
    • Затем установим TypeScript Beta в качестве зависимости:
      npm i -D typescript@beta
      TypeScript Beta установит в dev-зависимости TypeScript 5.0 Beta.

    Важно: если на момент прочтения уже вышла стабильная версия, вы можете использовать ее.

    Теперь нужно сделать сборку. Для этого переходим в tsconfig.json, находим параметр outDir и задаем его значение равным ./dist, чтобы все наши транспилированные файлы сохранялись внутри директории dist:

    "outDir": "./dist",
    

    В файле package.json создаем несколько скриптов:

    • Первый - это скрипт build, который отвечает за сборку приложения. Он будет использовать локально установленную версию TypeScript:
      json "build": "tsc",
    • Второй скрипт - это start, который запускает приложение:
      json "start": "node ./dist/app.js"

    Кроме того, нам нужно создать файл app.ts, в котором мы будем экспериментировать.

    Декоратор метода

    Создадим класс Demo, который мы будем декорировать. У него будет метод exec, который принимает число и просто выводит это число с помощью console.log().

    class Demo {
        exec(a: number) {
            console.log(a);
        }
    }
    

    Добавляем декоратор methodDec:

    class Demo {
    
        @methodDec
        exec(a: number) {
            console.log(a);
        }
    }
    

    Все декораторы - это просто функции, которые всегда принимают два аргумента: target, который мы декорируем, и context - это контекст нашего декоратора. При этом декораторы, теоретически, могут быть универсальными, использоваться одновременно как на методе, так и на классе.

    Для типизации добавим немного Generics: This - это ссылка на наш класс, Args - это массив аргументов типа any, а Return - это тип возвращаемого значения нашего метода:

    function methodDec<This, Args extends any[], Return>(
        target: (this: This, ...args: Args) => Return,
        context
    ) {
    
    }
    

    Для context у нас есть ClassMethodDecoratorContext - это контекст декоратора:

    function methodDec<This, Args extends any[], Return>(
        target: (this: This, ...args: Args) => Return,
        context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return> 
    )
    

    Сам декоратор метода возвращает функцию где мы может изменить поведение исходного метода:

    class Demo {
    
        @methodDec 
        exec(a: number) {
            console.log(a);
        }
    }
    
    function methodDec<This, Args extends any[], Return>(
        target: (this: This, ...args: Args) => Return,
        context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>
    ) {
         console.log('Init method');
         return function(this: This, ...args: Args): Return {
              const res = target.call(this, ...args);
             return res;
        }
    }
    
    const demo = new Demo();
    demo.exec(1);
    

    Чтобы проверить, что наш декоратор работает, необходимо ввести команды npm run build и npm start:

    Init method
    1
    

    Пример - Декоратор Max number

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

    Max - это функция, которая принимает число, больше которого аргумент передать нельзя:

    class Demo {
        @Max(10)
        exec(a: number) {
            console.log(a);
        }
    }
    
    function Max(num: number) {
        return function <This, Args extends any[], Return>(
            target: (this: This, ...args: Args) => Return,
            context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>
        ) {
              return function(this: This, ...args: Args): Return {
                    if (args[0] > num) {
                        throw new Error(`Значение больше ${num}`)
                    }
                   const res = target.call(this, ...args);
                  return res;
                }
        }
    } 
    
    const demo = new Demo();
    demo.exec(1);
    demo.exec(11);
    

    После выполнения в во втором вызове получаем ошибку, так как значение больше 10.

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

    Декоратор класса

    Декоратор класса у нас принимает target - это new (…args: Args) и возвращает наш This, а в качестве контекста он использует ClassDecoratorContext с описанием самого класса:

    @classDec
    class Demo {
        @Max(10)
        exec(a: number) {
            console.log(a);
        }
    }
    
    // код
    
    function classDec<This, Args extends any[]>(
        target: new (...args: Args) => This,
        context: ClassDecoratorContext<new (...args: Args) => This>
    ) {
         console.log('Class init');
    }
    
    const demo = new Demo();
    demo.exec(1);
    

    Одно из частых использований такого декоратора, которое можно увидеть в библиотеках – это Dependency Injection.

    Декоратор поля

    У декоратора поля есть следующие параметры: target, у которого значение будет undefined, и context, у которого будет ClassFieldDecoratorContext.

    Кстати, не путайте с предыдущими версиями декораторов, у которых нет приставки “Context”. В этом случае вы можете получить неправильную типизацию.

    Контекст принимает This и тип, в данном случае - string. В отличие от остальных, он может возвращать модифицированную функцию инициализации:

    @classDec
    class Demo {
        @fieldDec
        name: string = 'Test';
    
        @Max(10)
        exec(a: number) {
            console.log(a);
        }
    }
    
    // код
    
    function fieldDec<This>(
        target: undefined,
        context: ClassFieldDecoratorContext<This, string>
    ) {
            console.log('Field init');
            return function (value: string) {
                console.log('Field init function')
                return value;
          }
    }
    
    // код
    

    Мы можем модифицировать поведение только один раз при инициализации. Но на текущий момент не все функции декоратора доступны, поэтому в будущем будет возможно реализовать изменение поведение при get и set.

    Декоратор setter

    Очень похож на декоратор метода, но имеет другую типизацию ClassSetterDecoratorContext:

    @classDec
    class Demo {
        private _surname!: string;
    
        @fieldDec
        name: string = 'Test';
    
        @setDec
        set surname(value: string) {
            this._surname = value;
        }
    
        @Max(10)
        exec(a: number) {
            console.log(a);
        }
    }
    
    function setDec<This, Return>(
        target: (this: This, arg: any) => Return,
        context: ClassSetterDecoratorContext<This, (this: This, arg: any) => Return>
    ) {
         console.log('Init method');
         return function (this: This, arg: any): Return {
             const res = target.call(this, arg);
             return res;
         }
    }
    
    // код
    

    Пример - setter проверка на строку

    Сделаем декоратор @IsString:

    @classDec
    class Demo {
        private _surname!: string;
    
        @fieldDec
        name: string = 'Test';
    
        @IsString
        set surname(value: string) {
            this._surname = value;
        }
    
        @Max(10)
        exec(a: number) {
            console.log(a);
        }
    }
    
    // код
    
    function IsString<This, Return>(
        target: (this: This, arg: any) => Return,
        context: ClassSetterDecoratorContext<This, (this: This, arg: any) => Return>
    ) {
         console.log('Set method');
         return function (this: This, arg: any): Return {
             if (typeof arg !== 'string') {
                 throw new Error ('Не строка')
             }
             const res = target.call(this, arg);
             return res;
         }
    }
    
    // код
    
    const demo = new Demo();
    demo.exec(1);
    

    При этом декораторы могут стекаться друг на друга. Например, мы можем поставить один декоратор над другим, и тогда первый декоратор обернёт функцию, а второй декоратор обернёт результат выполнения первого декоратора. И это большое преимущество декораторов - мы можем комбинировать их для создания более сложной функциональности.

    Иконка глаза6 699

    Комментарии

    0

    Постройте личный план изучения Основы разработки до уровня Middle — бесплатно!

    Основы разработки — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Основы Git

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    HTML и CSS

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Neovim

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста Webpack vs Vite в 2025: что выбрать для нового проекта
    Иконка аватараАнтон
    Иконка календаря23 мая 2026
    webpackvitefrontend+ 2middleИконка уровня middle

    Webpack vs Vite в 2025: что выбрать для нового проекта

    Сравнение Webpack и Vite в 2025 году: скорость сборки, конфигурация, HMR, экосистема. Что выбрать для нового проекта и почему.

    Иконка чипа0
    Иконка глаза12
    Иконка комментариев0
    Картинка поста Next.js для начинающих: роутинг, данные и первый деплой
    Иконка аватараАнтон
    Иконка календаря22 мая 2026
    Next.jsReactSSR+ 2juniorИконка уровня junior

    Next.js для начинающих: роутинг, данные и первый деплой

    Next.js для начинающих: разбираем файловый роутинг App Router, загрузку данных в серверных компонентах и первый деплой на Vercel за минуту.

    Иконка чипа0
    Иконка глаза50
    Иконка комментариев0
    Картинка поста Деплой Node.js на VPS за 30 минут: пошаговое руководство
    Иконка аватараАнтон
    Иконка календаря21 мая 2026
    Node.jsVPSDevOps+ 3middleИконка уровня middle

    Деплой Node.js на VPS за 30 минут: пошаговое руководство

    Деплой Node.js на VPS за 30 минут: настройка сервера, PM2, Nginx и SSL. Пошаговая инструкция от подключения по SSH до запуска приложения в продакшене.

    Иконка чипа0
    Иконка глаза80
    Иконка комментариев0
    Иконка чипа0