javascript - Hvordan fikse problem med metodeoverlasting i Angular 4, med forskjellige datatyper?


Dette er min demokode:

class First {
    x: string;
    y: string;
    constructor() 
    {
    }
    setValue(x: string, y: string): void {
        this.x = x;
        this.y = y;
        console.log("setValue In A value of x and y:", this.x, this.y);
    }
    getValue(): void {
        console.log("getValue In A value of x and y:", this.x, this.y);
    }
}

class Second extends First {
    x: string = '5';
    z: number;
    constructor() {
        super();
    }

    setValue(z: number, y: string) {
        this.z = z;
        this.y = y;
        return super.setValue(this.x, this.y); 
    }
}

Jeg har to klasser, Første og Andre. Men i klasse Andre får jeg følgende feil

Eiendom 'setValue' i typen 'Second' kan ikke tildeles den samme eiendommen i basetypen 'First'. Typen '(z: number, y: string) => void' kan ikke tildeles typen '(x: string, y: string) => void'. Typene til parametrene 'z' og 'x' er inkompatible. Typen 'string' kan ikke tilordnes typen 'number'

Jeg prøvde med noen mulige løsninger ved å gi typen som 'any' i den første metoden i klassen, og prøvde også med en annen løsning ved å gi unionstype i den andre klassen som z: string | number

Men begge løsningene er lappetepper mot problemet, men kan ikke løse det opprinnelige problemet, da vi kan sende en streng eller et tall, men faktisk godtar det bare streng. For å gjøre det klarere, hvis vi antar at metoden bare aksepterer ett argument, vil ingen av de ovennevnte løsningene fungere.

Jeg håper det er klart med mitt problem.

Svar #1

Problemet er at det du prøver å gjøre bryter med OOP-prinsipper. Hvis vi antar at overbelastningen du ønsker ville være tillatt, vurder følgende kode:

let f: First = new Second() // Assign a derived class to a base type reference
f.setValue("Not a number", "y") // Second is getting a string insead of a number

I koden ovenfor vil Second motta som det første argumentet en string i stedet for et tall siden vi kaller gjennom en referanse til en baseklasse.

En løsning er å beholde både den opprinnelige signaturen og legge til signaturen med nummeret, og sørge for at begge fungerer som forventet:

class First {
    x: string;
    y: string;
    constructor() 
    {
    }
    setValue(x: string, y: string): void {
        this.x = x;
        this.y = y;
        console.log("setValue In A value of x and y:", this.x, this.y);
    }
    getValue(): void {
        console.log("getValue In A value of x and y:", this.x, this.y);
    }
}

class Second extends First {
    x: string = '5';
    z: number;
    constructor() {
        super();
    }

    setValue(x: string, y: string)
    setValue(z: number, y: string)
    setValue(xz: string | number, y: string) {
      if (typeof xz == 'number') {
        this.z = xz; // xz is number so we got called with z
        this.y = y;
        return super.setValue(this.x, this.y);
      } else {
        // xz is string so we got called with x
        return super.setValue(xz, y);
      } 
    }
}

let f: First = new Second() // Assign a derived class to a base type reference
f.setValue("Not a number", "y") // Works as expected now

Generelt, når du utleder klasser, kan du legge til i klassens offentlige signatur, men du kan ikke fjerne fra den, da det ville bryte prinsippet i OOP om at du trygt kan tilordne en utledet klasse til en baseklasse-referanse.

Merk Typescript er veldig fleksibelt med typene sine, og du kan gjøre litt typekirurgi for å fjerne setValue fra First for å ha en høyere grad av frihet i Second. Jeg kan tilby en slik løsning, men jeg anbefaler det på det sterkeste ikke.