javascript - Bevara typsignaturen när en funktion som lämnats som parameter returneras


Jag har en funktion som kallas conditional som tar emot ett booleskt värde och en funktion, och returnerar den funktionen om det booleska värdet är sant, annars returnerar den en dummyfunktion.

function conditional(x, f) {
  if(x)
    return f
  else
    return () => {}
}

Så, jag kan köra kod på det här sättet:

let mySqrt = conditional(true, Math.sqrt)
let add = (x, y) => x + y
let myAdd = conditional(true, add)

Men när jag lägger till typer till den villkorliga funktionen, går typdefinitionen för funktionen som skickas till conditional-funktionen förlorad. Och detta gör det möjligt att skriva kod som mySqrt("a") utan att TypeScript klagar.

Hur lägger jag till typer till den villkorliga funktionen så att typen på den resulterande funktionen bevaras?

Svar #1

Du behöver använda en generisk typparameter för att representera typen av funktionen:

function conditional<T extends (...args: any[]) => any>(x: boolean, f: T): T {
    if (x)
        return f;
    else
        return (() => { }) as any; // we need an assertion here to make the empty function compatible with T
}

// Usage
let mySqrt = conditional(true, Math.sqrt); //mySqrt will be of type (x: number) => number
let add = (x: number, y: number) => x + y;
let myAdd = conditional(true, add); // myAdd will be of type (x: number, y: number) => number

Svar #2

Du kan använda en kombination av generiska typer och metodöverlagringssignaturer.

function conditional<T extends Function>(x: true, f: T): T;
function conditional<T extends Function>(x: false, f: T): () => {};
function conditional<T extends Function>(x: boolean, f: T) {
  if(x)
    return f
  else
    return () => {}
}

let mySqrt = conditional(true, Math.sqrt)
mySqrt('a') // error

När man tillhandahåller överlagrade metodsignaturer kommer kompilatorn att dölja den faktiska, mer flexibla implementeringen.