Декоратор метода TypeScript - `this` с включенным noImplicitThis

Я пытаюсь написать простой декоратор метода, который выполняет простую логику перед вызовом исходного метода. Все примеры, которые я смог найти, сводятся к вызову originalMethod.apply(this, args) в конце, но с включенным noImplicitThis в tsconfig.json я получаю следующую ошибку:

[eval].ts(1,224): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.

Я попытался обойтись, позвонив в originalMethod.apply(this as any, args), но ошибка не исчезла.

Вопрос: Существуют ли какие-либо обходные пути для вызова исходного метода, без с отключением noImplicitThis для всего проекта?


Минимальный пример - работает с отключенным noImplicitAny:

function logBeforeCall1(): originalMethodDecorator {
    return function(
        target: any,
        propertyKey: string | symbol,
        descriptor: PropertyDescriptor,
    ): PropertyDescriptor {
        const originalMethod = descriptor.value;
        descriptor.value = (...args: any[]) => {
            console.info('hello!');
            return originalMethod.apply(this, args);
        };
        return descriptor;
    };
}

class Test1 {
    private num: number = 1;

    @logBeforeCall1()
    test(next: number): void {
        console.info(this.num, '->', next);
        this.num = next;
    }
}

  • Я уже знаю, что декораторы не имеют доступа к конкретному экземпляру объекта (см., Например, этот вопрос), но использование this в приведенном выше примере работает.
  • Официальные документы по декораторам используют конструкцию из моего примера (см. Раздел "Декораторы недвижимости"), поэтому она работает, но конфликтует с опцией компилятора noImplicitThis ...
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
5
0
2 846
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я не думаю, что вы действительно можете получить безопасность типов, но если вы просто хотите избавиться от ошибки типа, вы можете явно указать, что this: any (3-я строка):

function logBeforeCall1() {
  return function (
    this: any,
    target: any,
    propertyKey: string | symbol,
    descriptor: PropertyDescriptor,
  ): PropertyDescriptor {
    const originalMethod = descriptor.value;
    descriptor.value = (...args: any[]) => {
      console.info('hello!');
      return originalMethod.apply(this, args);
    };
    return descriptor;
  };
}

Это компилируется, но не выполняется во время выполнения: `test (next) {console.info (this.num, '->', next); this.num = следующий; } `-> TypeError: Cannot read property 'num' of undefined at test ([eval].ts:5:35)

quezak 19.12.2018 09:52

Но, вдохновленный вашим ответом, я нашел решение - аргумент this нужно добавить к фактическому замещаемому методу, а не к функции декоратора.

quezak 19.12.2018 09:58
Ответ принят как подходящий

Спасибо @Grassator за вдохновение - эта версия работает. Однако я не верю, что это можно сделать с безопасным типом в текущем состоянии TypeScript.

function logBeforeCall2(): originalMethodDecorator {
    return function(
        target: any,
        propertyKey: string | symbol,
        descriptor: PropertyDescriptor,
    ): PropertyDescriptor {
        const originalMethod = descriptor.value;
        descriptor.value = function(this: any, ...args: any[]): any {
            console.info('hello!');
            return originalMethod.apply(this, args);
        };
        return descriptor;
    };
}

...

> t2.test(5)
hello!
1 '->' 5

Другие вопросы по теме