Struggling to incorporate a pause decorator into my application, I encountered difficulties while trying to understand a related issue

I am currently working with a service file that contains the following:

export class MockDataService {
   data:[] = [];

   getAll(): Observable<any[]> { return of(this.data); }
}

To introduce a delay to my mocks, I decided to use a @pause() decorator to wrap around all the functions:

export async function pause() {
    await new Promise( res => setTimeout(res, 1500) );
}

In order to add a pause of 1.5 seconds to all endpoints, I applied it to the getAll() function like so:

@pause()
getAll() {}

However, I encountered an error message when using it in my code. The error stated:

Unable to resolve signature of method decorator when called as an expression. Cannot invoke an expression whose type lacks a call signature. Type 'Promise<void>' has no compatible call signatures.

I am currently trying to understand why my function signatures might be incorrect. Additionally, I plan to use Http calls within these functions, so I believed I had the correct function definition.

Answer №1

The reason for the error you are encountering is due to the specific signature that the Method decorator must adhere to:

declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;

The Method decorator cannot return a Promise<void>. It is required to either return TypedPropertyDescriptor<T> or be void. Since you are working with Observable<>, you should utilize the delay operator from rxjs/operators:

export function observablePause(
  target: Object,
  propertyName: string,
  propertyDesciptor: PropertyDescriptor): PropertyDescriptor {
  const method = propertyDesciptor.value;

  propertyDesciptor.value = function (...args: any[]) {

      // execute the decorated method and capture its return value
      let result = <Observable<any>>method.apply(this, args);
      // introducing a delay
      result = result.pipe(delay(1500));
      // return the result of the method invocation
      return result;
  }
  return propertyDesciptor;
};
...
@observablePause
getAll(): Observable<any[]> { return of(this.data); }

Answer №2

If you use this code, you will receive your wait time, but it is possible that there are other issues to consider with the observable response.

@Injectable({
  providedIn: 'root'
})
export class MockDataService {

  data: [] = [];

  @delay()
  downloadData() {
    return this.data;
  }

  getAll(): Observable<any[]> {
    return of(this.downloadData());
  }

  constructor() {
  }
}

export function delay(): MethodDecorator {
  return function(target: Function, key: string, descriptor: any) {

    const originalMethod = descriptor.value;

    descriptor.value =  async function(...args: any[]) {
      console.log('Entering Wait!');
      await new Promise(res => setTimeout(res, 1500));
      console.log('Completed Wait!');
      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using Typescript to reduce an array of objects results in concatenation

In my quest to calculate the sum of integers from an array of objects stored in a redux slice, I have encountered a challenge. Here is the code snippet in question: export type Expense = { id: string; title: string; amount: number; date: st ...

Employing async/await for efficient data retrieval

Attempting to utilize async-await in TypeScript Vue 3 to retrieve data, but encountering an issue where the function is already logging 'undefined' (or executing before the function call) private async exportDataOrder() { await this.getDataEx ...

What could be the reason my component is not displaying the ContentChild associated with a directive?

It appears that utilizing a directive to target a content child from another directive is the recommended approach (source). However, why isn't my component able to recognize the component marked with the directive? ./my.component.ts import { Comp ...

What is the best way to leverage the Nextjs Link tag while also incorporating the data-dismiss attribute?

Currently, I am working on a Next.js project. In the mobile view, my navigation menu utilizes a modal to toggle the navbar. However, I have encountered an issue where when I click on a navigation link, the data gets dismissed but the link itself does not n ...

Tips for integrating JavaScript libraries into TypeScript build process in Visual Studio

Is it possible to configure the "TypeScript Build" feature in Visual Studio 2017 to include both Javascript libraries and TypeScript files in the generated bundle.js output? ...

Is there an alternative to RequestOptionsArgs that I can use in this function?

I am currently working on updating an existing Angular application from version 4.3 to Angular 8. One of the challenges I'm facing is replacing old component classes like ConnectionBackend, RequestOptions, and RequestOptionsArgs with their updated equ ...

Passing data to a redirected route in Angular using the redirectTo parameter

Is there a way to send the "data" to the home component only when redirected from an old path, and not from an empty path? const routes: Routes = [ {path : '', redirectTo:'home'}, {path : 'oldPath', redirectTo:&apo ...

limit the data types of values within an object using Typescript

When working with typescript, how can I define the type signature for a plain old javascript object that allows any key, but restricts the values to strings only? For example, {a:"foo"} and {b:"bar"} are considered valid values, while {a:[1,2,3]} and {b:3} ...

AngularFire UPDATE -> APPLY CHANGES

I can't seem to figure this out. I'm wondering how to UPDATE a document that is returned in the WHERE clause using AngularFire: constructor(private db: AngularFirestore) { } var path = this.db.collection('users').doc('type') ...

Guide on updating a property key in Firebase real-time database with Angular 7

Is it possible to modify the key of a property in my firebase database that I have been struggling with? ...

The incorrect type is being assigned to an array of enum values in Typescript

Here's some code that I've been working on: enum AnimalId { Dog = 2, Cat = 3 } const animalIds: AnimalId[] = [AnimalId.Dog, 4]; I'm curious as to why TypeScript isn't flagging the assignment of 4 to type AnimalId[]. Shouldn't ...

Tips for showcasing JSON data in an HTML table or list

I am seeking a way to dynamically display changing JSON object data in a table using Angular. The structure of the JSON object is subject to change due to server updates. JSON Object: { "This item has 1 value":1, "Another":30, "It ...

TypeScript Error 2304: Element 'div' is nowhere to be found - CRA TypeScript Template

I'm experiencing a problem in VSCode while working on the default create-react-app my-app --template typescript project. It seems to not recognize any HTML elements, as I keep getting the error cannot find name xxx, where 'xxx' represents th ...

Despite being listed in the entry components, HelloComponent is not actually included in the NgModule

Check out my StackBlitz demo where I am experimenting with dynamically instantiating the HelloComponent using the ReflexiveInjector. The HelloComponent is added to the app modules entryComponents array. Despite this setup, I am still encountering the foll ...

Angular form submission encountered an error

Encountered a JSON decode error from the Laravel API when attempting to submit form data. Unable to access the Laravel API side, but the submission is successful when done via Swagger. curl -X 'POST' \ 'https://example.com/create-refe ...

Tips on integrating Ionic 2 with Angular 2 services

I'm a beginner with Ionic 2. I came across information in the Angular 2 documentation stating that services need to be injected during application bootstrapping. However, I didn't see any mention of bootstrapping while following the Ionic 2 tuto ...

Validating React components with TypeScript using an array structure where the field name serves as the key

Trying to implement form validation with React. I have a main Controller that contains the model and manages the validation process. The model is passed down to child controllers along with the validation errors. I am looking for a way to create an array ...

In the CallableFunction.call method, the keyword "extends keyof" is transformed into "never"

In the following method, the type of the second parameter (loadingName) is determined by the key of the first parameter. (alias) function withLoading<T, P extends keyof T>(this: T, loadingName: P, before: () => Promise<any>): Promise<void ...

Which types of mouse events are compatible with Angular2?

Exploring mouse events in Angular2 has sparked my curiosity. I have implemented the click event, but now I wonder what other mouse events are available, such as mouseover. Where can I find a comprehensive list of mouse events supported by Angular2? The o ...

The response URL in Angular 2 is logged character by character instead of as one complete string

Hello, I am a beginner in the world of Angular 2 and I am currently working on obtaining the response URL in the following manner. .map(res => res.url); --this code is part of my service .subscribe(data => { for (let entry of data){ this.test = ...