javascript - Angular: skicka en metod som parameter


Jag har dessa två metoder som nästan är lika:

private firstFunction () {
    this.serviceOne.methodOne().subscribe(
      res => {
        return  resultOne = res;
      },
      err => {}
    );
  }

private secondFunction () {
    this.serviceTwo.methodTwo().subscribe(
      res => {
        return  resultTwo = res;
      },
      err => {}
    );
  }

Jag vill skriva en generell funktion, som denna:

genericFunction (service ,method , result  ) {
        service.method().subscribe(
          res => {
            return  result = res;
          },
          err => {}
        );
      }

Och följaktligen vill jag få något liknande detta att fungera:

genericFunction (serviceOne , methodOne , resultOne );
genericFunction (serviceTwo , methodTwo , resultTwo );

Faktiskt kan jag inte hitta hur man skickar methodOne och methodTwo som parametrar. Några förslag?

Svar #1

Det finns flera problem i din kod.

För det första vill du ändra fältet som du skickar in som en parameter (som föreslaget av result=res). Du kan inte skicka in en referens till ett fält, men du kan skicka in fältnamnet och använda indexering för att ändra fältet. keyof T kommer att låta dig skicka in fältet på ett typ-säkert sätt.

För det andra, om du vill komma åt en metod på en tjänst. Återigen kan vi göra detta genom att skicka in metodnamnet, och vi kan begränsa tjänsten till att ha en metod med det inskickade metodnamnet, som returnerar en Observable. Resultatet av Observable kan också begränsas till att vara av samma typ som fältet vi ska tilldela det till för att metoden ska vara helt typ säker.

declare class Service1 {
    method1() : Observable<number>
}
declare class Service2 {
    method2() : Observable<string>
}
class MyClass {
    resultOne!: number;
    resultTwo!: string;

    constructor() {
        this.genericFunction(new Service1(), "method1", "resultOne");
        this.genericFunction(new Service2(), "method2", "resultTwo");
        this.genericFunction(new Service1(), "method1", "resultTwo"); // error resultTwo is a string, the method return Observable<number>
        this.genericFunction(new Service2(), "method", "resultTwo"); // error method does not exit on Service2
        this.genericFunction(new Service2(), "method2", "resultTwo2"); // error field does not exist on type 
    }

    genericFunction<MethodKey extends string,  ResultKey  extends keyof MyClass>(service:Record<MethodKey, ()=> Observable<MyClass[ResultKey]>>, method:MethodKey, result: ResultKey){
        service[method]().subscribe(
            res => this[result] = res,
            err => {}
        );
    }
}

Notera Vi skulle också kunna ha skickat in funktionen som en funktion, inte bara som ett namn, utan direkt som en typad funktion. Nackdelen med detta är att vi antingen måste använda bind för att säkerställa att servicemetoden fortfarande har korrekt this när den kallas, eller använda en pilfunktion vid anrop (återigen för att säkerställa att servicemetoden har korrekt this). Detta är dock felbenäget, bind resulterar i en otypad funktion, så vi kan inte kontrollera kompatibilitet med fältet, och någon kan passa service.method direkt och inget fel skulle rapporteras förrän vid körning:

class MyClass {
    resultOne!: number;
    resultTwo!: string;

    constructor() {
        var service1 = new Service1()
        var service2 = new Service2()
        this.genericFunction(()=> service1.method1(), "resultOne");
        this.genericFunction(()=> service2.method2(), "resultTwo");

        this.genericFunction(service2.method2, "resultTwo"); // no error, depending on the implementation of method2 it might or might not work
        this.genericFunction(service2.method2.bind(service2), "resultOne"); // no error, the service call will work, but we store it in an incompatible variable
        this.genericFunction(()=> service1.method1(), "resultTwo");// error resultTwo is a string, the method return Observable<number>
        this.genericFunction(()=> service2.method2(), "resultTwo2");// // error field does not exist on type 
    }

    genericFunction<MethodKey extends string,  ResultKey  extends keyof MyClass>(method:()=> Observable<MyClass[ResultKey]>, result: ResultKey){
        method().subscribe(
            res => this[result] = res,
            err => {}
        );
    }
}

Svar #2

försök med att använda följande kod:

private firstFunction () {
    let response= genericFunction(this.serviceOne.methodOne())      
}
private secondFunction () {
   let response = genericFunction(this.serviceTwo.methodTwo())    
}

Ändra din generiska funktion genom att bara ta emot en variabel.

//if it is angular 4 or less
genericFunction (method: Observable) {
        return method.map(res => {
           return res.json();
        });
      }
 //if it is angular 5 or 6
 genericFunction (method: Observable) {
        return method.pipe(            
           map(res => {
           return res;
        }));
      }

Relaterade artiklar