typescript - Hvordan definere type for en funksjonscallback (som en hvilken som helst funksjonstype, ikke universell any) brukt som en metodeparameter


Akkurat nå har jeg typedefinisjon som:

interface Param {
    title: string;
    callback: any;
}

Jeg trenger noe som:

interface Param {
    title: string;
    callback: function;
}

men den andre blir ikke akseptert.

Svar #1

Den globale typen Function tjener dette formålet.

I tillegg, hvis du har til hensikt å påkalle denne callbacken med 0 argumenter og vil ignorere returverdien, passer typen () => void for alle funksjoner som ikke tar noen argumenter.

Svar #2

Typescript fra v1.4 har nøkkelordet type som erklærer et typealias (tilsvarende en typedef i C/C++). Du kan erklære callback-typen din slik:

type CallbackFunction = () => void;

som erklærer en funksjon som ikke tar noen argumenter og ikke returnerer noe. En funksjon som tar null eller flere argumenter av hvilken som helst type og ikke returnerer noe, ville være:

type CallbackFunctionVariadic = (...args: any[]) => void;

Da kan du for eksempel si,

let callback: CallbackFunctionVariadic = function(...args: any[]) {
  // do some stuff
};

Hvis du vil ha en funksjon som tar et vilkårlig antall argumenter og returnerer hva som helst (inkludert void):

type CallbackFunctionVariadicAnyReturn = (...args: any[]) => any;

Du kan spesifisere noen obligatoriske argumenter og deretter et sett med ekstra argumenter (for eksempel en streng, et tall og deretter et sett med ekstra argumenter) slik:

type CallbackFunctionSomeVariadic =
  (arg1: string, arg2: number, ...args: any[]) => void;

Dette kan være nyttig for ting som EventEmitter-håndterere.

Funksjoner kan typiseres så sterkt du vil på denne måten, selv om du kan bli revet med og støte på kombinatoriske problemer hvis du prøver å spikre alt med en typealias.

Svar #3

Som en oppfølging av Ryans svar, tror jeg at grensesnittet du ser etter er definert som følger:

interface Param {
    title: string;
    callback: () => void;
}

Svar #4

Du kan definere en funksjonstype i et grensesnitt på ulike måter,

  1. generell måte:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. Hvis du ønsker å bruke egenskapssyntaks, så
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. Hvis du først erklærer funkjonstypen, så
type MyFnType = (arg1: number, arg2: number) => number;

export interface IParam {
  title: string;
  callback: MyFnType;
}

Bruk er veldig enkelt.

function callingFn(paramInfo: IParam):number {
    let needToCall = true;
    let result = 0;
   if(needToCall){
     result = paramInfo.callback(1,2);
    }

    return result;
}
  1. Du kan også erklære en funksjonstype-literal, som betyr at en funksjon kan akseptere en annen funksjon som sin parameter. En parameterisert funksjon kan også kalles som en tilbakekalling.
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}

Svar #5

Her er et eksempel på en funksjon som aksepterer en tilbakekalling

const sqk = (x: number, callback: ((_: number) => number)): number => {
  // callback will receive a number and expected to return a number
  return callback (x * x);
}

// here our callback will receive a number
sqk(5, function(x) {
  console.log(x); // 25
  return x;       // we must return a number here
});

Hvis du ikke bryr deg om returverdiene til callback-funksjoner (de fleste vet ikke hvordan de skal bruke dem på en effektiv måte), kan du bruke void

const sqk = (x: number, callback: ((_: number) => void)): void => {
  // callback will receive a number, we don't care what it returns
  callback (x * x);
}

// here our callback will receive a number
sqk(5, function(x) {
  console.log(x); // 25
  // void
});

Merk, signaturen jeg brukte for callback-parameteren ...

const sqk = (x: number, callback: ((_: number) => number)): number

Jeg vil si at dette er en TypeScript-mangel fordi vi forventes å oppgi et navn for tilbakemeldingsparametrene. I dette tilfellet brukte jeg _ fordi det ikke er brukbart inne i sqk-funksjonen.

Men, hvis du gjør dette

// danger!! don't do this
const sqk = (x: number, callback: ((number) => number)): number

Det er gyldig TypeScript, men det vil bli tolket som ...

// watch out! typescript will think it means ...
const sqk = (x: number, callback: ((number: any) => number)): number

Ie, TypeScript vil tro at parameteren name er number og den implisitte typen er any. Dette er åpenbart ikke det vi hadde til hensikt, men ak, det er slik TypeScript fungerer.

Så ikke glem å oppgi parameterne når du skriver inn funksjonsparametrene dine... dumt som det kan virke.

Svar #6

Det finnes ulike måter å definere funksjonstyper på; likevel er noen bedre enn andre.

Selv om det er mulig å bruke Function, JavaScript-funksjonsobjektet, ikke gjør det.
Kilde: TypeScript ESLint-plugin anbefalt regel ban-types

  • Unngå Funksjon-typen, da den gir liten sikkerhet av følgende grunner:

    • Det gir ingen typesikkerhet når verdien kalles, noe som betyr at det er lett å gi feil argumenter.
    • Den aksepterer klassedeklarasjoner, som vil feile når de kalles, ettersom de kalles uten nøkkelordet new.

TypeScript støtter flere andre måter. For eksempel funksjonstypeuttrykk. Denne metoden ligner sterkt på pilfunksjoner.

Hvis argumenter og returverdier er kjent for å ha en bestemt form, bør de typeres. Dette bør være tilfelle for en callback.
For eksempel,

interface Param {
  callback: (foo: string, bar: number) => void
}

Merk at disse typene kan være så komplekse som nødvendig, for eksempel ved å bruke objekttyper eller typer laget fra andre typer.

Hvis typene virkelig er ukjente, bør du foretrekke unknown fremfor any.
Kilde: TypeScript ESLint-plugin anbefalt regel no-explicit-any

Når any brukes, blir alle kompilatortypekontroller rundt den verdien ignorert.

Fra TS-dokumentasjonen,

unknown er den typesikre motparten til any.

Dermed, ved å bruke spread-syntaks,

interface Param {
  callback: (...args: unknown[]) => unknown
}

Svar #7

Det finnes fire abstrakte funksjonstyper, du kan bruke dem separat når du vet om funksjonen din vil ta et argument(er) eller ikke, og om den vil returnere data eller ikke.

export declare type fEmptyVoid = () => void;
export declare type fEmptyReturn = () => any;
export declare type fArgVoid = (...args: any[]) => void;
export declare type fArgReturn = (...args: any[]) => any;

som dette:

public isValid: fEmptyReturn = (): boolean => true;
public setStatus: fArgVoid = (status: boolean): void => this.status = status;

For bruk bare én type som hvilken som helst funksjonstype kan vi kombinere alle abstrakte typer sammen, slik:

export declare type fFunction = fEmptyVoid | fEmptyReturn | fArgVoid | fArgReturn;

bruk det da slik:

public isValid: fFunction = (): boolean => true;
public setStatus: fFunction = (status: boolean): void => this.status = status;

I eksemplet ovenfor er alt korrekt. Men brukseksemplet nedenfor er ikke korrekt sett fra synspunktet til de fleste kodeeditorer.

// you can call this function with any type of function as argument
public callArgument(callback: fFunction) {

    // but you will get editor error if call callback argument like this
    callback();
}

Riktig kall for redaktører er slik:

public callArgument(callback: fFunction) {

    // pay attention in this part, for fix editor(s) error
    (callback as fFunction)();
}

Relaterte artikler